rework pinch-zoom image view to use ImageMatrixTouchHandler
kill video surface in fragment onpause
This commit is contained in:
parent
bb32ac7dc4
commit
15cda36008
@ -28,6 +28,7 @@ dependencies {
|
||||
compile project(':taskerlocaleapi')
|
||||
compile files('libs/dashclock-api-r1.1.jar')
|
||||
compile 'org.jsoup:jsoup:1.10.2'
|
||||
compile 'com.bogdwellers:pinchtozoom:0.1'
|
||||
compile 'com.github.bumptech.glide:glide:3.8.0'
|
||||
compile 'jp.wasabeef:glide-transformations:2.0.2'
|
||||
compile 'com.android.support:cardview-v7:25.3.1'
|
||||
|
@ -1,268 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,509 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
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 );
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
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();
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package it.sephiroth.android.library.imagezoom.utils;
|
||||
|
||||
public interface IDisposable {
|
||||
|
||||
void dispose();
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package org.fox.ttrss;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import it.sephiroth.android.library.imagezoom.ImageViewTouch;
|
||||
|
||||
public class ArticleImagesPager extends android.support.v4.view.ViewPager {
|
||||
public ArticleImagesPager(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
|
||||
if (v instanceof ImageViewTouch) {
|
||||
ImageViewTouch ivt = (ImageViewTouch) v;
|
||||
try {
|
||||
return ivt.canScroll(dx);
|
||||
} catch (NullPointerException e) {
|
||||
// bad image, etc
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return super.canScroll(v, checkV, dx, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
return super.onInterceptTouchEvent(event);
|
||||
}
|
||||
}
|
@ -22,10 +22,12 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.ToxicBakery.viewpager.transforms.DepthPageTransformer;
|
||||
import com.bogdwellers.pinchtozoom.ImageMatrixTouchHandler;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
|
||||
@ -42,10 +44,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import it.sephiroth.android.library.imagezoom.ImageViewTouch;
|
||||
import me.relex.circleindicator.CircleIndicator;
|
||||
|
||||
public class ArticleImagesPagerActivity extends CommonActivity implements GestureDetector.OnDoubleTapListener {
|
||||
public class ArticleImagesPagerActivity extends CommonActivity {
|
||||
private final String TAG = this.getClass().getSimpleName();
|
||||
|
||||
private ArrayList<String> m_urls;
|
||||
@ -53,25 +54,9 @@ public class ArticleImagesPagerActivity extends CommonActivity implements Gestur
|
||||
private String m_title;
|
||||
private ArticleImagesPagerAdapter m_adapter;
|
||||
private String m_content;
|
||||
private GestureDetector m_detector;
|
||||
private ProgressBar m_progress;
|
||||
private ViewPager m_pager;
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
|
||||
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;
|
||||
|
||||
@ -101,21 +86,11 @@ public class ArticleImagesPagerActivity extends CommonActivity implements Gestur
|
||||
|
||||
View view = inflater.inflate(R.layout.article_images_image, null);
|
||||
|
||||
m_detector = new GestureDetector(ArticleImagesPagerActivity.this, new GestureDetector.SimpleOnGestureListener());
|
||||
ImageView imgView = (ImageView) view.findViewById(R.id.flavor_image);
|
||||
|
||||
m_detector.setOnDoubleTapListener(ArticleImagesPagerActivity.this);
|
||||
ImageMatrixTouchHandler touchHandler = new ImageMatrixTouchHandler(view.getContext());
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
imgView.setOnTouchListener(touchHandler);
|
||||
|
||||
// shared element transitions stop GIFs from playing
|
||||
if (position == 0 && url.toLowerCase().indexOf(".gif") == -1) {
|
||||
@ -174,10 +149,6 @@ public class ArticleImagesPagerActivity extends CommonActivity implements Gestur
|
||||
})
|
||||
.into(glideImage);
|
||||
|
||||
/*if (position == 0) {
|
||||
ActivityCompat.startPostponedEnterTransition(ArticleImagesPagerActivity.this);
|
||||
}*/
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@ -196,15 +167,6 @@ public class ArticleImagesPagerActivity extends CommonActivity implements Gestur
|
||||
if (!isCancelled()) {
|
||||
position++;
|
||||
|
||||
//Log.d(TAG, "checking: " + url);
|
||||
|
||||
/*DisplayImageOptions options = new DisplayImageOptions.Builder()
|
||||
.cacheInMemory(true)
|
||||
.cacheOnDisk(true)
|
||||
.build();
|
||||
|
||||
Bitmap bmp = ImageLoader.getInstance().loadImageSync(url, options); */
|
||||
|
||||
try {
|
||||
Bitmap bmp = Glide.with(ArticleImagesPagerActivity.this)
|
||||
.load(url)
|
||||
|
@ -1312,12 +1312,16 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
||||
if (m_mediaPlayer != null) {
|
||||
m_mediaPlayer.release();
|
||||
}
|
||||
try {
|
||||
if (m_mediaPlayer != null) {
|
||||
m_mediaPlayer.release();
|
||||
}
|
||||
|
||||
if (m_activeSurface != null) {
|
||||
m_activeSurface.setVisibility(View.GONE);
|
||||
if (m_activeSurface != null) {
|
||||
m_activeSurface.setVisibility(View.GONE);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
m_mediaPlayer = new MediaPlayer();
|
||||
@ -1807,4 +1811,23 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
|
||||
m_articles.addAll(articles);
|
||||
m_adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
try {
|
||||
if (m_mediaPlayer != null) {
|
||||
m_mediaPlayer.release();
|
||||
}
|
||||
|
||||
if (m_activeSurface != null) {
|
||||
m_activeSurface.setVisibility(View.GONE);
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,260 +0,0 @@
|
||||
package org.fox.ttrss.util;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Tomáš Procházka
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Special version of ImageView which allow enlarge width of image if android:adjustViewBounds is true.
|
||||
*
|
||||
* <p>It simulate HTML behaviour <img src="" widh="100" /></p>
|
||||
* <p><a href="http://stackoverflow.com/questions/6202000/imageview-one-dimension-to-fit-free-space-and-second-evaluate-to-keep-aspect-rati">Stackoverflow question link</a></p>
|
||||
*
|
||||
* <p>It also allow set related view which will be used as reference for size measure.</p>
|
||||
*
|
||||
* @author Tomáš Procházka <<a href="mailto:tomas.prochazka@inmite.eu">tomas.prochazka@gmail.com</a>>
|
||||
* @version $Revision: 0$ ($Date: 6.6.2011 18:16:52$)
|
||||
*/
|
||||
public class EnlargingImageView extends ForegroundImageView {
|
||||
|
||||
private int mDrawableWidth;
|
||||
private int mDrawableHeight;
|
||||
private boolean mAdjustViewBoundsL;
|
||||
private int mMaxWidthL = Integer.MAX_VALUE;
|
||||
private int mMaxHeightL = Integer.MAX_VALUE;
|
||||
private View relatedView;
|
||||
|
||||
public EnlargingImageView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
// hack for acces some private field of parent :-(
|
||||
Field f;
|
||||
try {
|
||||
f = android.widget.ImageView.class.getDeclaredField("mAdjustViewBounds");
|
||||
f.setAccessible(true);
|
||||
setAdjustViewBounds((Boolean) f.get(this));
|
||||
|
||||
f = android.widget.ImageView.class.getDeclaredField("mMaxWidth");
|
||||
f.setAccessible(true);
|
||||
setMaxWidth((Integer) f.get(this));
|
||||
|
||||
f = android.widget.ImageView.class.getDeclaredField("mMaxHeight");
|
||||
f.setAccessible(true);
|
||||
setMaxHeight((Integer) f.get(this));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public EnlargingImageView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public EnlargingImageView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void setAdjustViewBounds(boolean adjustViewBounds) {
|
||||
super.setAdjustViewBounds(adjustViewBounds);
|
||||
mAdjustViewBoundsL = adjustViewBounds;
|
||||
}
|
||||
|
||||
public void setMaxWidth(int maxWidth) {
|
||||
super.setMaxWidth(maxWidth);
|
||||
mMaxWidthL = maxWidth;
|
||||
}
|
||||
|
||||
public void setMaxHeight(int maxHeight) {
|
||||
super.setMaxHeight(maxHeight);
|
||||
mMaxHeightL = maxHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
if (getDrawable() == null) {
|
||||
setMeasuredDimension(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
mDrawableWidth = getDrawable().getIntrinsicWidth();
|
||||
mDrawableHeight = getDrawable().getIntrinsicHeight();
|
||||
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
|
||||
// Desired aspect ratio of the view's contents (not including padding)
|
||||
float desiredAspect = 0.0f;
|
||||
|
||||
// We are allowed to change the view's width
|
||||
boolean resizeWidth = false;
|
||||
|
||||
// We are allowed to change the view's height
|
||||
boolean resizeHeight = false;
|
||||
|
||||
if (mDrawableWidth > 0) {
|
||||
w = mDrawableWidth;
|
||||
h = mDrawableHeight;
|
||||
if (w <= 0) w = 1;
|
||||
if (h <= 0) h = 1;
|
||||
|
||||
// We are supposed to adjust view bounds to match the aspect
|
||||
// ratio of our drawable. See if that is possible.
|
||||
if (mAdjustViewBoundsL) {
|
||||
|
||||
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
|
||||
resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
|
||||
resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
|
||||
|
||||
desiredAspect = (float) w / (float) h;
|
||||
}
|
||||
}
|
||||
|
||||
int pleft = getPaddingLeft();
|
||||
int pright = getPaddingRight();
|
||||
int ptop = getPaddingTop();
|
||||
int pbottom = getPaddingBottom();
|
||||
|
||||
int widthSize;
|
||||
int heightSize;
|
||||
|
||||
if (resizeWidth || resizeHeight) {
|
||||
/* If we get here, it means we want to resize to match the
|
||||
drawables aspect ratio, and we have the freedom to change at
|
||||
least one dimension.
|
||||
*/
|
||||
|
||||
// Get the max possible width given our constraints
|
||||
widthSize = resolveAdjustedSize(w + pleft + pright,
|
||||
mMaxWidthL, widthMeasureSpec);
|
||||
|
||||
// Get the max possible height given our constraints
|
||||
heightSize = resolveAdjustedSize(h + ptop + pbottom,
|
||||
mMaxHeightL, heightMeasureSpec);
|
||||
|
||||
if (desiredAspect != 0.0f) {
|
||||
// See what our actual aspect ratio is
|
||||
float actualAspect = (float) (widthSize - pleft - pright) /
|
||||
(heightSize - ptop - pbottom);
|
||||
|
||||
if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
|
||||
|
||||
// Try adjusting width to be proportional to height
|
||||
if (resizeWidth) {
|
||||
int newWidth = (int) (desiredAspect * (heightSize - ptop - pbottom)) + pleft + pright;
|
||||
|
||||
if (newWidth > 0 && widthSize > 0 && newWidth / widthSize > 2)
|
||||
newWidth = widthSize * 2;
|
||||
|
||||
if (/*newWidth <= widthSize &&*/ newWidth > 0) {
|
||||
widthSize = Math.min(newWidth, mMaxWidthL);
|
||||
heightSize = (int) ((widthSize - pleft - pright) / desiredAspect) + ptop + pbottom;
|
||||
}
|
||||
}
|
||||
|
||||
// Try adjusting height to be proportional to width
|
||||
if (resizeHeight) {
|
||||
int newHeight = (int) ((widthSize - pleft - pright) / desiredAspect) + ptop + pbottom;
|
||||
|
||||
if (newHeight > 0 && heightSize > 0 && newHeight / heightSize > 2)
|
||||
newHeight = heightSize * 2;
|
||||
|
||||
if (/* newHeight <= heightSize && */ newHeight > 0) {
|
||||
heightSize = Math.min(newHeight, mMaxHeightL);
|
||||
widthSize = (int) (desiredAspect * (heightSize - ptop - pbottom)) + pleft + pright;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* We are either don't want to preserve the drawables aspect ratio,
|
||||
or we are not allowed to change view dimensions. Just measure in
|
||||
the normal way.
|
||||
*/
|
||||
w += pleft + pright;
|
||||
h += ptop + pbottom;
|
||||
|
||||
w = Math.max(w, getSuggestedMinimumWidth());
|
||||
h = Math.max(h, getSuggestedMinimumHeight());
|
||||
|
||||
widthSize = resolveSize(w, widthMeasureSpec);
|
||||
heightSize = resolveSize(h, heightMeasureSpec);
|
||||
}
|
||||
|
||||
//Log.d(Constants.LOGTAG, mDrawableWidth + ":" + mDrawableHeight + " to " + widthSize + ":" + heightSize);
|
||||
|
||||
setMeasuredDimension(widthSize, heightSize);
|
||||
|
||||
if (relatedView != null) {
|
||||
//Log.i(Constants.LOGTAG, getTag() + " onMeasure:" + widthSize + ", " + heightSize + " update size of related view!");
|
||||
relatedView.getLayoutParams().width = widthSize;
|
||||
relatedView.getLayoutParams().height = heightSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
//Log.d(Constants.LOGTAG, getTag() + " onLayout:" + left + ", " + top + ", " + right + ", " + bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Experimental. This view will be set to the same size as this image.
|
||||
*/
|
||||
public void setRelatedView(View view) {
|
||||
relatedView = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
//Log.d(Constants.LOGTAG, getTag() + " onSizeChanged:" + w + ", " + h + ", " + oldw + ", " + oldh);
|
||||
}
|
||||
|
||||
private int resolveAdjustedSize(int desiredSize, int maxSize, int measureSpec) {
|
||||
int result = desiredSize;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
switch (specMode) {
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
/* Parent says we can be as big as we want. Just don't be larger
|
||||
than max size imposed on ourselves.
|
||||
*/
|
||||
result = Math.min(desiredSize, maxSize);
|
||||
break;
|
||||
case MeasureSpec.AT_MOST:
|
||||
// Parent says we can be as big as we want, up to specSize.
|
||||
// Don't be larger than specSize, and don't be larger than
|
||||
// the max size imposed on ourselves.
|
||||
result = Math.min(Math.min(desiredSize, specSize), maxSize);
|
||||
break;
|
||||
case MeasureSpec.EXACTLY:
|
||||
// No choice. Do what we are told.
|
||||
result = specSize;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
package org.fox.ttrss.util;
|
||||
|
||||
// https://gist.github.com/JakeWharton/0a251d67649305d84e8a
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.fox.ttrss.R;
|
||||
|
||||
public class ForegroundImageView extends ImageView {
|
||||
private Drawable foreground;
|
||||
|
||||
public ForegroundImageView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ForegroundImageView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ForegroundImageView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundImageView);
|
||||
Drawable foreground = a.getDrawable(R.styleable.ForegroundImageView_android_foreground);
|
||||
if (foreground != null) {
|
||||
setForeground(foreground);
|
||||
}
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply a drawable resource that is to be rendered on top of all of the child
|
||||
* views in the frame layout.
|
||||
*
|
||||
* @param drawableResId The drawable resource to be drawn on top of the children.
|
||||
*/
|
||||
public void setForegroundResource(int drawableResId) {
|
||||
setForeground(getContext().getResources().getDrawable(drawableResId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply a Drawable that is to be rendered on top of all of the child
|
||||
* views in the frame layout.
|
||||
*
|
||||
* @param drawable The Drawable to be drawn on top of the children.
|
||||
*/
|
||||
public void setForeground(Drawable drawable) {
|
||||
if (foreground == drawable) {
|
||||
return;
|
||||
}
|
||||
if (foreground != null) {
|
||||
foreground.setCallback(null);
|
||||
unscheduleDrawable(foreground);
|
||||
}
|
||||
|
||||
foreground = drawable;
|
||||
|
||||
if (drawable != null) {
|
||||
drawable.setCallback(this);
|
||||
if (drawable.isStateful()) {
|
||||
drawable.setState(getDrawableState());
|
||||
}
|
||||
}
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override protected boolean verifyDrawable(Drawable who) {
|
||||
return super.verifyDrawable(who) || who == foreground;
|
||||
}
|
||||
|
||||
@Override public void jumpDrawablesToCurrentState() {
|
||||
super.jumpDrawablesToCurrentState();
|
||||
if (foreground != null) foreground.jumpToCurrentState();
|
||||
}
|
||||
|
||||
@Override protected void drawableStateChanged() {
|
||||
super.drawableStateChanged();
|
||||
if (foreground != null && foreground.isStateful()) {
|
||||
foreground.setState(getDrawableState());
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (foreground != null) {
|
||||
foreground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
if (foreground != null) {
|
||||
foreground.setBounds(0, 0, w, h);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void draw(Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
|
||||
if (foreground != null) {
|
||||
foreground.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void drawableHotspotChanged(float x, float y) {
|
||||
super.drawableHotspotChanged(x, y);
|
||||
|
||||
if (foreground != null && android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
foreground.setHotspot(x, y);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/flavor_image_progress" />
|
||||
|
||||
<it.sephiroth.android.library.imagezoom.ImageViewTouch
|
||||
<ImageView
|
||||
android:id="@+id/flavor_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -6,7 +6,7 @@
|
||||
android:background="@android:color/black"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<org.fox.ttrss.ArticleImagesPager
|
||||
<com.bogdwellers.pinchtozoom.view.ImageViewPager
|
||||
android:id="@+id/article_images_pager"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
|
@ -49,7 +49,4 @@
|
||||
<attr format="reference|color" name="insetForeground">
|
||||
</attr></declare-styleable>
|
||||
<attr name="drawer_header" format="reference" />
|
||||
<declare-styleable name="ForegroundImageView">
|
||||
<attr name="android:foreground"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
Loading…
Reference in New Issue
Block a user