implement resizeable imageview for image pager

This commit is contained in:
Andrew Dolgov 2014-11-25 12:19:36 +03:00
parent 1accc3749f
commit 4ac2b72796
9 changed files with 957 additions and 4 deletions

View File

@ -0,0 +1,268 @@
package it.sephiroth.android.library.imagezoom;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.ViewConfiguration;
public class ImageViewTouch extends ImageViewTouchBase {
private static final float SCROLL_DELTA_THRESHOLD = 1.0f;
static final float MIN_ZOOM = 0.9f;
protected ScaleGestureDetector mScaleDetector;
protected GestureDetector mGestureDetector;
protected int mTouchSlop;
protected float mCurrentScaleFactor;
protected float mScaleFactor;
protected int mDoubleTapDirection;
protected OnGestureListener mGestureListener;
protected OnScaleGestureListener mScaleListener;
protected boolean mDoubleTapToZoomEnabled = true;
protected boolean mScaleEnabled = true;
protected boolean mScrollEnabled = true;
private OnImageViewTouchDoubleTapListener doubleTapListener;
public interface OnScaleChangedListener {
public void onScaleChanged(float scale);
}
protected OnScaleChangedListener mScaleChangedListener;
public ImageViewTouch( Context context, AttributeSet attrs ) {
super( context, attrs );
}
@Override
protected void init() {
super.init();
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mGestureListener = getGestureListener();
mScaleListener = getScaleListener();
mScaleDetector = new ScaleGestureDetector( getContext(), mScaleListener );
mGestureDetector = new GestureDetector( getContext(), mGestureListener, null, true );
mCurrentScaleFactor = 1f;
mDoubleTapDirection = 1;
}
public void setDoubleTapListener( OnImageViewTouchDoubleTapListener doubleTapListener ){
this.doubleTapListener = doubleTapListener;
}
public void setDoubleTapToZoomEnabled( boolean value ) {
mDoubleTapToZoomEnabled = value;
}
public void setScaleEnabled( boolean value ) {
mScaleEnabled = value;
}
public void setScrollEnabled( boolean value ) {
mScrollEnabled = value;
}
public boolean getDoubleTapEnabled() {
return mDoubleTapToZoomEnabled;
}
protected OnGestureListener getGestureListener() {
return new GestureListener();
}
protected OnScaleGestureListener getScaleListener() {
return new ScaleListener();
}
@Override
protected void onBitmapChanged( Drawable drawable ) {
super.onBitmapChanged( drawable );
float v[] = new float[9];
mSuppMatrix.getValues( v );
mCurrentScaleFactor = v[Matrix.MSCALE_X];
}
@Override
protected void _setImageDrawable( final Drawable drawable, final boolean reset, final Matrix initial_matrix, final float maxZoom ) {
super._setImageDrawable( drawable, reset, initial_matrix, maxZoom );
mScaleFactor = getMaxZoom() / 3;
}
@Override
public boolean onTouchEvent( MotionEvent event ) {
mScaleDetector.onTouchEvent( event );
if ( !mScaleDetector.isInProgress() ) mGestureDetector.onTouchEvent( event );
int action = event.getAction();
switch ( action & MotionEvent.ACTION_MASK ) {
case MotionEvent.ACTION_UP:
if ( getScale() < 1f ) {
zoomTo( 1f, 50 );
}
break;
}
return true;
}
@Override
protected void onZoom( float scale ) {
super.onZoom( scale );
if ( !mScaleDetector.isInProgress() ) mCurrentScaleFactor = scale;
if (mScaleChangedListener != null) {
mScaleChangedListener.onScaleChanged(mCurrentScaleFactor);
}
}
protected float onDoubleTapPost( float scale, float maxZoom ) {
if ( mDoubleTapDirection == 1 ) {
if (mCurrentScaleFactor - 1.0f < 0.01) { //( scale + ( mScaleFactor * 2 ) ) <= maxZoom
float scaleFactor = mScaleFactor;
RectF bitmapRect = getBitmapRect();
float w = bitmapRect.right - bitmapRect.left;
float h = bitmapRect.bottom - bitmapRect.top;
if (w < getWidth()) {
scaleFactor = (float)getWidth() / w - scale;
} else if (h < getHeight()) {
scaleFactor = (float)getHeight() / h - scale;
}
return scale + scaleFactor;
} else {
mDoubleTapDirection = -1;
return maxZoom;
}
} else {
mDoubleTapDirection = 1;
return 1f;
}
}
/**
* Determines whether this ImageViewTouch can be scrolled.
* @param direction
* - positive direction value means scroll from right to left,
* negative value means scroll from left to right
*
* @return true if there is some more place to scroll, false - otherwise.
*/
public boolean canScroll(int direction) {
RectF bitmapRect = getBitmapRect();
updateRect(bitmapRect, mScrollRect);
Rect imageViewRect = new Rect();
getGlobalVisibleRect(imageViewRect);
if (bitmapRect.right >= imageViewRect.right) {
if (direction < 0) {
return Math.abs(bitmapRect.right - imageViewRect.right) > SCROLL_DELTA_THRESHOLD;
}
}
double bitmapScrollRectDelta = Math.abs(bitmapRect.left - mScrollRect.left);
return bitmapScrollRectDelta > SCROLL_DELTA_THRESHOLD;
}
public class GestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onDoubleTap( MotionEvent e ) {
Log.i( LOG_TAG, "onDoubleTap. double tap enabled? " + mDoubleTapToZoomEnabled);
if (mDoubleTapToZoomEnabled) {
float scale = getScale();
float targetScale = scale;
targetScale = onDoubleTapPost( scale, getMaxZoom() );
targetScale = Math.min( getMaxZoom(), Math.max( targetScale, MIN_ZOOM ) );
mCurrentScaleFactor = targetScale;
zoomTo( targetScale, e.getX(), e.getY(), 200 );
invalidate();
}
if( null != doubleTapListener ){
doubleTapListener.onDoubleTap();
}
return super.onDoubleTap( e );
}
@Override
public void onLongPress( MotionEvent e ) {
if ( isLongClickable() ) {
if ( !mScaleDetector.isInProgress() ) {
setPressed( true );
performLongClick();
}
}
}
@Override
public boolean onScroll( MotionEvent e1, MotionEvent e2, float distanceX, float distanceY ) {
if ( !mScrollEnabled ) return false;
if ( e1 == null || e2 == null ) return false;
if ( e1.getPointerCount() > 1 || e2.getPointerCount() > 1 ) return false;
if ( mScaleDetector.isInProgress() ) return false;
if ( getScale() == 1f ) return false;
scrollBy( -distanceX, -distanceY );
invalidate();
return super.onScroll( e1, e2, distanceX, distanceY );
}
@Override
public boolean onFling( MotionEvent e1, MotionEvent e2, float velocityX, float velocityY ) {
if ( !mScrollEnabled ) return false;
if ( e1.getPointerCount() > 1 || e2.getPointerCount() > 1 ) return false;
if ( mScaleDetector.isInProgress() ) return false;
float diffX = e2.getX() - e1.getX();
float diffY = e2.getY() - e1.getY();
if ( Math.abs( velocityX ) > 800 || Math.abs( velocityY ) > 800 ) {
scrollBy( diffX / 2, diffY / 2, 300 );
invalidate();
}
return super.onFling( e1, e2, velocityX, velocityY );
}
}
public class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@SuppressWarnings("unused")
@Override
public boolean onScale( ScaleGestureDetector detector ) {
float span = detector.getCurrentSpan() - detector.getPreviousSpan();
float targetScale = mCurrentScaleFactor * detector.getScaleFactor();
if ( mScaleEnabled ) {
targetScale = Math.min( getMaxZoom(), Math.max( targetScale, MIN_ZOOM ) );
zoomTo( targetScale, detector.getFocusX(), detector.getFocusY() );
mCurrentScaleFactor = Math.min( getMaxZoom(), Math.max( targetScale, MIN_ZOOM ) );
mDoubleTapDirection = 1;
invalidate();
return true;
}
return false;
}
}
public interface OnImageViewTouchDoubleTapListener {
void onDoubleTap();
}
public void setOnScaleChangedListener(OnScaleChangedListener listener) {
mScaleChangedListener = listener;
}
}

View File

@ -0,0 +1,509 @@
package it.sephiroth.android.library.imagezoom;
import it.sephiroth.android.library.imagezoom.easing.Cubic;
import it.sephiroth.android.library.imagezoom.easing.Easing;
import it.sephiroth.android.library.imagezoom.graphics.FastBitmapDrawable;
import it.sephiroth.android.library.imagezoom.utils.IDisposable;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
/**
* Base View to manage image zoom/scrool/pinch operations
*
* @author alessandro
*
*/
public class ImageViewTouchBase extends ImageView implements IDisposable {
public interface OnBitmapChangedListener {
void onBitmapChanged( Drawable drawable );
};
public static final String LOG_TAG = "image";
protected Easing mEasing = new Cubic();
protected Matrix mBaseMatrix = new Matrix();
protected Matrix mSuppMatrix = new Matrix();
protected Handler mHandler = new Handler();
protected Runnable mOnLayoutRunnable = null;
protected float mMaxZoom;
protected final Matrix mDisplayMatrix = new Matrix();
protected final float[] mMatrixValues = new float[9];
protected int mThisWidth = -1, mThisHeight = -1;
protected boolean mFitToScreen = false;
protected boolean mFitToWidth = false;
final protected float MAX_ZOOM = 3.0f;
protected RectF mBitmapRect = new RectF();
protected RectF mCenterRect = new RectF();
protected RectF mScrollRect = new RectF();
private OnBitmapChangedListener mListener;
public ImageViewTouchBase( Context context ) {
super( context );
init();
}
public ImageViewTouchBase( Context context, AttributeSet attrs ) {
super( context, attrs );
init();
}
public void setOnBitmapChangedListener( OnBitmapChangedListener listener ) {
mListener = listener;
}
protected void init() {
setScaleType( ImageView.ScaleType.MATRIX );
}
public void clear() {
setImageBitmap( null, true );
}
public void setFitToScreen( boolean value ) {
if ( value != mFitToScreen ) {
mFitToScreen = value;
requestLayout();
}
}
public void setFitToWidth( boolean value ) {
if ( value != mFitToWidth ) {
mFitToWidth = value;
requestLayout();
}
}
@Override
protected void onLayout( boolean changed, int left, int top, int right, int bottom ) {
super.onLayout( changed, left, top, right, bottom );
mThisWidth = right - left;
mThisHeight = bottom - top;
Runnable r = mOnLayoutRunnable;
if ( r != null ) {
mOnLayoutRunnable = null;
r.run();
}
if ( getDrawable() != null ) {
if ( mFitToScreen )
getProperBaseMatrix2( getDrawable(), mBaseMatrix );
else
getProperBaseMatrix( getDrawable(), mBaseMatrix );
setImageMatrix( getImageViewMatrix() );
if (mFitToWidth) zoomToWidth();
}
}
@Override
public void setImageBitmap( Bitmap bm ) {
setImageBitmap( bm, true );
}
@Override
public void setImageResource( int resId ) {
setImageDrawable( getContext().getResources().getDrawable( resId ) );
}
/**
* Set the new image to display and reset the internal matrix.
*
* @param bitmap
* - the {@link Bitmap} to display
* @param reset
* - if true the image bounds will be recreated, otherwise the old {@link Matrix} is used to display the new bitmap
* @see #setImageBitmap(Bitmap)
*/
public void setImageBitmap( final Bitmap bitmap, final boolean reset ) {
setImageBitmap( bitmap, reset, null );
}
/**
* Similar to {@link #setImageBitmap(Bitmap, boolean)} but an optional view {@link Matrix} can be passed to determine the new
* bitmap view matrix.<br />
* This method is useful if you need to restore a Bitmap with the same zoom/pan values from a previous state
*
* @param bitmap
* - the {@link Bitmap} to display
* @param reset
* @param matrix
* - the {@link Matrix} to be used to display the new bitmap
*
* @see #setImageBitmap(Bitmap, boolean)
* @see #setImageBitmap(Bitmap)
* @see #getImageViewMatrix()
* @see #getDisplayMatrix()
*/
public void setImageBitmap( final Bitmap bitmap, final boolean reset, Matrix matrix ) {
setImageBitmap( bitmap, reset, matrix, -1 );
}
/**
*
* @param bitmap
* @param reset
* @param matrix
* @param maxZoom
* - maximum zoom allowd during zoom gestures
*
* @see #setImageBitmap(Bitmap, boolean, Matrix)
*/
public void setImageBitmap( final Bitmap bitmap, final boolean reset, Matrix matrix, float maxZoom ) {
Log.i( LOG_TAG, "setImageBitmap: " + bitmap );
if ( bitmap != null )
setImageDrawable( new FastBitmapDrawable( bitmap ), reset, matrix, maxZoom );
else
setImageDrawable( null, reset, matrix, maxZoom );
}
@Override
public void setImageDrawable( Drawable drawable ) {
setImageDrawable( drawable, true, null, -1 );
}
public void setImageDrawable( final Drawable drawable, final boolean reset, final Matrix initial_matrix, final float maxZoom ) {
final int viewWidth = getWidth();
if ( viewWidth <= 0 ) {
mOnLayoutRunnable = new Runnable() {
@Override
public void run() {
setImageDrawable( drawable, reset, initial_matrix, maxZoom );
}
};
return;
}
_setImageDrawable( drawable, reset, initial_matrix, maxZoom );
}
protected void _setImageDrawable( final Drawable drawable, final boolean reset, final Matrix initial_matrix, final float maxZoom ) {
if ( drawable != null ) {
if ( mFitToScreen )
getProperBaseMatrix2( drawable, mBaseMatrix );
else
getProperBaseMatrix( drawable, mBaseMatrix );
super.setImageDrawable( drawable );
if (mFitToWidth) zoomToWidth();
} else {
mBaseMatrix.reset();
super.setImageDrawable( null );
}
if ( reset ) {
mSuppMatrix.reset();
if ( initial_matrix != null ) {
mSuppMatrix = new Matrix( initial_matrix );
}
}
setImageMatrix( getImageViewMatrix() );
if ( maxZoom < 1 )
mMaxZoom = maxZoom();
else
mMaxZoom = maxZoom;
onBitmapChanged( drawable );
}
protected void onBitmapChanged( final Drawable bitmap ) {
if ( mListener != null ) {
mListener.onBitmapChanged( bitmap );
}
}
protected float maxZoom() {
final Drawable drawable = getDrawable();
if ( drawable == null ) {
return 1F;
}
float fw = (float) drawable.getIntrinsicWidth() / (float) mThisWidth;
float fh = (float) drawable.getIntrinsicHeight() / (float) mThisHeight;
float max = Math.max( fw, fh ) * 4;
return max;
}
public float getMaxZoom() {
return mMaxZoom;
}
public Matrix getImageViewMatrix() {
mDisplayMatrix.set( mBaseMatrix );
mDisplayMatrix.postConcat( mSuppMatrix );
return mDisplayMatrix;
}
/**
* Returns the current image display matrix. This matrix can be used in the next call to the
* {@link #setImageBitmap(Bitmap, boolean, Matrix)} to restore the same view state of the previous {@link Bitmap}
*
* @return
*/
public Matrix getDisplayMatrix() {
return new Matrix( mSuppMatrix );
}
/**
* Setup the base matrix so that the image is centered and scaled properly.
*
* @param bitmap
* @param matrix
*/
protected void getProperBaseMatrix( Drawable drawable, Matrix matrix ) {
float viewWidth = getWidth();
float viewHeight = getHeight();
float w = drawable.getIntrinsicWidth();
float h = drawable.getIntrinsicHeight();
matrix.reset();
if ( w > viewWidth || h > viewHeight ) {
float widthScale = Math.min( viewWidth / w, 2.0f );
float heightScale = Math.min( viewHeight / h, 2.0f );
float scale = Math.min( widthScale, heightScale );
matrix.postScale( scale, scale );
float tw = ( viewWidth - w * scale ) / 2.0f;
float th = ( viewHeight - h * scale ) / 2.0f;
matrix.postTranslate( tw, th );
} else {
float tw = ( viewWidth - w ) / 2.0f;
float th = ( viewHeight - h ) / 2.0f;
matrix.postTranslate( tw, th );
}
}
/**
* Setup the base matrix so that the image is centered and scaled properly.
*
* @param bitmap
* @param matrix
*/
protected void getProperBaseMatrix2( Drawable bitmap, Matrix matrix ) {
float viewWidth = getWidth();
float viewHeight = getHeight();
float w = bitmap.getIntrinsicWidth();
float h = bitmap.getIntrinsicHeight();
matrix.reset();
float widthScale = Math.min( viewWidth / w, MAX_ZOOM );
float heightScale = Math.min( viewHeight / h, MAX_ZOOM );
float scale = Math.min( widthScale, heightScale );
matrix.postScale( scale, scale );
matrix.postTranslate( ( viewWidth - w * scale ) / 2.0f, ( viewHeight - h * scale ) / 2.0f );
}
protected float getValue( Matrix matrix, int whichValue ) {
matrix.getValues( mMatrixValues );
return mMatrixValues[whichValue];
}
protected RectF getBitmapRect() {
final Drawable drawable = getDrawable();
if ( drawable == null ) return null;
Matrix m = getImageViewMatrix();
mBitmapRect.set( 0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight() );
m.mapRect( mBitmapRect );
return mBitmapRect;
}
protected float getScale( Matrix matrix ) {
return getValue( matrix, Matrix.MSCALE_X );
}
public float getRotation() {
return 0;
}
public float getScale() {
return getScale( mSuppMatrix );
}
protected void center( boolean horizontal, boolean vertical ) {
// Log.i(LOG_TAG, "center");
final Drawable drawable = getDrawable();
if ( drawable == null ) return;
RectF rect = getCenter( horizontal, vertical );
if ( rect.left != 0 || rect.top != 0 ) {
postTranslate( rect.left, rect.top );
}
}
protected RectF getCenter( boolean horizontal, boolean vertical ) {
final Drawable drawable = getDrawable();
if ( drawable == null ) return new RectF( 0, 0, 0, 0 );
RectF rect = getBitmapRect();
float height = rect.height();
float width = rect.width();
float deltaX = 0, deltaY = 0;
if ( vertical ) {
int viewHeight = getHeight();
if ( height < viewHeight ) {
deltaY = ( viewHeight - height ) / 2 - rect.top;
} else if ( rect.top > 0 ) {
deltaY = -rect.top;
} else if ( rect.bottom < viewHeight ) {
deltaY = getHeight() - rect.bottom;
}
}
if ( horizontal ) {
int viewWidth = getWidth();
if ( width < viewWidth ) {
deltaX = ( viewWidth - width ) / 2 - rect.left;
} else if ( rect.left > 0 ) {
deltaX = -rect.left;
} else if ( rect.right < viewWidth ) {
deltaX = viewWidth - rect.right;
}
}
mCenterRect.set( deltaX, deltaY, 0, 0 );
return mCenterRect;
}
protected void postTranslate( float deltaX, float deltaY ) {
mSuppMatrix.postTranslate( deltaX, deltaY );
setImageMatrix( getImageViewMatrix() );
}
protected void postScale( float scale, float centerX, float centerY ) {
mSuppMatrix.postScale( scale, scale, centerX, centerY );
setImageMatrix( getImageViewMatrix() );
}
protected void zoomTo( float scale ) {
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
zoomTo( scale, cx, cy );
}
public void zoomTo( float scale, float durationMs ) {
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;
zoomTo( scale, cx, cy, durationMs );
}
protected void zoomTo( float scale, float centerX, float centerY ) {
if ( scale > mMaxZoom ) scale = mMaxZoom;
float oldScale = getScale();
float deltaScale = scale / oldScale;
postScale( deltaScale, centerX, centerY );
onZoom( getScale() );
center( true, true );
}
protected void onZoom( float scale ) {}
public void scrollBy( float x, float y ) {
panBy( x, y );
}
protected void panBy( double dx, double dy ) {
RectF rect = getBitmapRect();
mScrollRect.set( (float) dx, (float) dy, 0, 0 );
updateRect( rect, mScrollRect );
postTranslate( mScrollRect.left, mScrollRect.top );
center( true, true );
}
protected void updateRect( RectF bitmapRect, RectF scrollRect ) {
float width = getWidth();
float height = getHeight();
if ( bitmapRect.top >= 0 && bitmapRect.bottom <= height ) scrollRect.top = 0;
if ( bitmapRect.left >= 0 && bitmapRect.right <= width ) scrollRect.left = 0;
if ( bitmapRect.top + scrollRect.top >= 0 && bitmapRect.bottom > height ) scrollRect.top = (int) ( 0 - bitmapRect.top );
if ( bitmapRect.bottom + scrollRect.top <= ( height - 0 ) && bitmapRect.top < 0 )
scrollRect.top = (int) ( ( height - 0 ) - bitmapRect.bottom );
if ( bitmapRect.left + scrollRect.left >= 0 ) scrollRect.left = (int) ( 0 - bitmapRect.left );
if ( bitmapRect.right + scrollRect.left <= ( width - 0 ) ) scrollRect.left = (int) ( ( width - 0 ) - bitmapRect.right );
// Log.d( LOG_TAG, "scrollRect(2): " + scrollRect.toString() );
}
protected void scrollBy( float distanceX, float distanceY, final double durationMs ) {
final double dx = distanceX;
final double dy = distanceY;
final long startTime = System.currentTimeMillis();
mHandler.post( new Runnable() {
double old_x = 0;
double old_y = 0;
@Override
public void run() {
long now = System.currentTimeMillis();
double currentMs = Math.min( durationMs, now - startTime );
double x = mEasing.easeOut( currentMs, 0, dx, durationMs );
double y = mEasing.easeOut( currentMs, 0, dy, durationMs );
panBy( ( x - old_x ), ( y - old_y ) );
old_x = x;
old_y = y;
if ( currentMs < durationMs ) {
mHandler.post( this );
} else {
RectF centerRect = getCenter( true, true );
if ( centerRect.left != 0 || centerRect.top != 0 ) scrollBy( centerRect.left, centerRect.top );
}
}
} );
}
protected void zoomTo( float scale, final float centerX, final float centerY, final float durationMs ) {
// Log.i( LOG_TAG, "zoomTo: " + scale + ", " + centerX + ": " + centerY );
final long startTime = System.currentTimeMillis();
final float incrementPerMs = ( scale - getScale() ) / durationMs;
final float oldScale = getScale();
mHandler.post( new Runnable() {
@Override
public void run() {
long now = System.currentTimeMillis();
float currentMs = Math.min( durationMs, now - startTime );
float target = oldScale + ( incrementPerMs * currentMs );
zoomTo( target, centerX, centerY );
if ( currentMs < durationMs ) {
mHandler.post( this );
} else {
// if ( getScale() < 1f ) {}
}
}
} );
}
@Override
public void dispose() {
clear();
}
protected void zoomToWidth() {
RectF bitmapRect = getBitmapRect();
float w = bitmapRect.right - bitmapRect.left;
if (w < getWidth()) {
float scale = (float)getWidth() / w;
zoomTo(scale, 0f, 0f);
}
}
}

View File

@ -0,0 +1,20 @@
package it.sephiroth.android.library.imagezoom.easing;
public class Cubic implements Easing {
@Override
public double easeOut( double time, double start, double end, double duration ) {
return end * ( ( time = time / duration - 1.0 ) * time * time + 1.0 ) + start;
}
@Override
public double easeIn( double time, double start, double end, double duration ) {
return end * ( time /= duration ) * time * time + start;
}
@Override
public double easeInOut( double time, double start, double end, double duration ) {
if ( ( time /= duration / 2.0 ) < 1.0 ) return end / 2.0 * time * time * time + start;
return end / 2.0 * ( ( time -= 2.0 ) * time * time + 2.0 ) + start;
}
}

View File

@ -0,0 +1,10 @@
package it.sephiroth.android.library.imagezoom.easing;
public interface Easing {
double easeOut( double time, double start, double end, double duration );
double easeIn( double time, double start, double end, double duration );
double easeInOut( double time, double start, double end, double duration );
}

View File

@ -0,0 +1,84 @@
package it.sephiroth.android.library.imagezoom.graphics;
import java.io.InputStream;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
/**
* Fast bitmap drawable. Does not support states. it only
* support alpha and colormatrix
* @author alessandro
*
*/
public class FastBitmapDrawable extends Drawable implements IBitmapDrawable {
protected Bitmap mBitmap;
protected Paint mPaint;
public FastBitmapDrawable( Bitmap b ) {
mBitmap = b;
mPaint = new Paint();
mPaint.setDither( true );
mPaint.setFilterBitmap( true );
}
public FastBitmapDrawable( Resources res, InputStream is ){
this(BitmapFactory.decodeStream(is));
}
@Override
public void draw( Canvas canvas ) {
canvas.drawBitmap( mBitmap, 0.0f, 0.0f, mPaint );
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha( int alpha ) {
mPaint.setAlpha( alpha );
}
@Override
public void setColorFilter( ColorFilter cf ) {
mPaint.setColorFilter( cf );
}
@Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
}
@Override
public int getIntrinsicHeight() {
return mBitmap.getHeight();
}
@Override
public int getMinimumWidth() {
return mBitmap.getWidth();
}
@Override
public int getMinimumHeight() {
return mBitmap.getHeight();
}
public void setAntiAlias( boolean value ){
mPaint.setAntiAlias( value );
invalidateSelf();
}
@Override
public Bitmap getBitmap() {
return mBitmap;
}
}

View File

@ -0,0 +1,14 @@
package it.sephiroth.android.library.imagezoom.graphics;
import it.sephiroth.android.library.imagezoom.ImageViewTouchBase;
import android.graphics.Bitmap;
/**
* Base interface used in the {@link ImageViewTouchBase} view
* @author alessandro
*
*/
public interface IBitmapDrawable {
Bitmap getBitmap();
}

View File

@ -0,0 +1,6 @@
package it.sephiroth.android.library.imagezoom.utils;
public interface IDisposable {
void dispose();
}

View File

@ -11,11 +11,14 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.util.Log;
import android.view.ContextMenu;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@ -38,7 +41,9 @@ import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
public class ArticleImagesPagerActivity extends CommonActivity {
import it.sephiroth.android.library.imagezoom.ImageViewTouch;
public class ArticleImagesPagerActivity extends CommonActivity implements GestureDetector.OnDoubleTapListener {
private final String TAG = this.getClass().getSimpleName();
private ArrayList<String> m_urls;
@ -46,6 +51,30 @@ public class ArticleImagesPagerActivity extends CommonActivity {
private String m_title;
private ArticleImagesPagerAdapter m_adapter;
private String m_content;
private GestureDetector m_detector;
@Override
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
ActionBar bar = getSupportActionBar();
if (bar.isShowing()) {
bar.hide();
} else {
bar.show();
}
return false;
}
@Override
public boolean onDoubleTap(MotionEvent motionEvent) {
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent motionEvent) {
return false;
}
private class ArticleImagesPagerAdapter extends PagerAdapter {
private List<String> m_urls;
@ -80,8 +109,21 @@ public class ArticleImagesPagerActivity extends CommonActivity {
View view = inflater.inflate(R.layout.article_images_image, null);
ImageView imgView = (ImageView) view.findViewById(R.id.flavor_image);
//imgView.setOnClickListener(this);
m_detector = new GestureDetector(ArticleImagesPagerActivity.this, new GestureDetector.SimpleOnGestureListener());
m_detector.setOnDoubleTapListener(ArticleImagesPagerActivity.this);
ImageViewTouch imgView = (ImageViewTouch) view.findViewById(R.id.flavor_image);
imgView.setFitToScreen(true);
imgView.setFitToWidth(true);
imgView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
return m_detector.onTouchEvent(event);
}
});
registerForContextMenu(imgView);

View File

@ -18,7 +18,7 @@
android:layout_gravity="center"
android:id="@+id/flavor_image_progress" />
<org.fox.ttrss.util.EnlargingImageView
<it.sephiroth.android.library.imagezoom.ImageViewTouch
android:id="@+id/flavor_image"
android:layout_width="match_parent"
android:layout_height="match_parent"