package com.mcxiaoke.minicat.ui.imagezoom; import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.ViewConfiguration; /** * @author mcxiaoke * @version 1.1 2011.11.22 */ public class ImageViewTouch extends ImageViewTouchBase { 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 GestureListener mGestureListener; protected ScaleListener mScaleListener; public ImageViewTouch(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void init() { super.init(); mTouchSlop = ViewConfiguration.getTouchSlop(); mGestureListener = new GestureListener(); mScaleListener = new ScaleListener(); // compatibility for api 7 mScaleDetector = new ScaleGestureDetector(getContext(), mScaleListener); // mGestureDetector = new GestureDetector( getContext(), // mGestureListener, null, true );// api>=8 mGestureDetector = new GestureDetector(getContext(), mGestureListener, null); mCurrentScaleFactor = 1f; mDoubleTapDirection = 1; } @Override public void setImageRotateBitmapReset(RotateBitmap bitmap, boolean reset) { super.setImageRotateBitmapReset(bitmap, reset); mScaleFactor = getMaxZoom() / 3; } @Override protected void onZoom(float scale) { super.onZoom(scale); if (!mScaleDetector.isInProgress()) mCurrentScaleFactor = scale; } @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; } protected float onDoubleTapPost(float scale, float maxZoom) { if (mDoubleTapDirection == 1) { if ((scale + (mScaleFactor * 2)) <= maxZoom) { return scale + mScaleFactor; } else { mDoubleTapDirection = -1; return maxZoom; } } else { mDoubleTapDirection = 1; return 1f; } } class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 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 (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); } @Override public boolean onDoubleTap(MotionEvent e) { 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(); return super.onDoubleTap(e); } } 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 (true) { 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; } } }