/******************************************************************************* * Copyright Alessandro Crugnola * * 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. *******************************************************************************/ package com.fanfou.app.opensource.ui.imagezoom; import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ViewConfiguration; import com.fanfou.app.opensource.ui.widget.ScaleGestureDetector; /** * @author mcxiaoke * @version 1.1 2011.11.22 * */ public class ImageViewTouch extends ImageViewTouchBase { class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDoubleTap(final MotionEvent e) { final float scale = getScale(); float targetScale = scale; targetScale = onDoubleTapPost(scale, getMaxZoom()); targetScale = Math.min(getMaxZoom(), Math.max(targetScale, ImageViewTouch.MIN_ZOOM)); ImageViewTouch.this.mCurrentScaleFactor = targetScale; zoomTo(targetScale, e.getX(), e.getY(), 200); invalidate(); return super.onDoubleTap(e); } @Override public boolean onFling(final MotionEvent e1, final MotionEvent e2, final float velocityX, final float velocityY) { if ((e1.getPointerCount() > 1) || (e2.getPointerCount() > 1)) { return false; } if (ImageViewTouch.this.mScaleDetector.isInProgress()) { return false; } final float diffX = e2.getX() - e1.getX(); final 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 onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX, final float distanceY) { if ((e1 == null) || (e2 == null)) { return false; } if ((e1.getPointerCount() > 1) || (e2.getPointerCount() > 1)) { return false; } if (ImageViewTouch.this.mScaleDetector.isInProgress()) { return false; } if (getScale() == 1f) { return false; } scrollBy(-distanceX, -distanceY); invalidate(); return super.onScroll(e1, e2, distanceX, distanceY); } } class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @SuppressWarnings("unused") @Override public boolean onScale(final ScaleGestureDetector detector) { final float span = detector.getCurrentSpan() - detector.getPreviousSpan(); float targetScale = ImageViewTouch.this.mCurrentScaleFactor * detector.getScaleFactor(); if (true) { targetScale = Math.min(getMaxZoom(), Math.max(targetScale, ImageViewTouch.MIN_ZOOM)); zoomTo(targetScale, detector.getFocusX(), detector.getFocusY()); ImageViewTouch.this.mCurrentScaleFactor = Math.min( getMaxZoom(), Math.max(targetScale, ImageViewTouch.MIN_ZOOM)); ImageViewTouch.this.mDoubleTapDirection = 1; invalidate(); return true; } return false; } } 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(final Context context, final AttributeSet attrs) { super(context, attrs); } @Override protected void init() { super.init(); this.mTouchSlop = ViewConfiguration.getTouchSlop(); this.mGestureListener = new GestureListener(); this.mScaleListener = new ScaleListener(); // compatibility for api 7 this.mScaleDetector = new ScaleGestureDetector(getContext(), this.mScaleListener); // mGestureDetector = new GestureDetector( getContext(), // mGestureListener, null, true );// api>=8 this.mGestureDetector = new GestureDetector(getContext(), this.mGestureListener, null); this.mCurrentScaleFactor = 1f; this.mDoubleTapDirection = 1; } protected float onDoubleTapPost(final float scale, final float maxZoom) { if (this.mDoubleTapDirection == 1) { if ((scale + (this.mScaleFactor * 2)) <= maxZoom) { return scale + this.mScaleFactor; } else { this.mDoubleTapDirection = -1; return maxZoom; } } else { this.mDoubleTapDirection = 1; return 1f; } } @Override public boolean onTouchEvent(final MotionEvent event) { this.mScaleDetector.onTouchEvent(event); if (!this.mScaleDetector.isInProgress()) { this.mGestureDetector.onTouchEvent(event); } final 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(final float scale) { super.onZoom(scale); if (!this.mScaleDetector.isInProgress()) { this.mCurrentScaleFactor = scale; } } @Override public void setImageRotateBitmapReset(final RotateBitmap bitmap, final boolean reset) { super.setImageRotateBitmapReset(bitmap, reset); this.mScaleFactor = getMaxZoom() / 3; } }