跟着hyman做的ZoomImageView,实现了双击放大,缩小,多指触碰放大缩小的功能;
import android.content.Context; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewTreeObserver; import android.widget.ImageView; /** * Created by Administrator on 2016/5/12. */ public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener, ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener { private Boolean first = false; private float initScale;//初始化的缩放量 private float maxScale;//最大缩放量 private float midScale;//中间缩放量 private Matrix matrix; private int lastTouchPointCount = 0;//上次屏幕触点数 private float lastX; private float lastY; private int onTouchSlop;//开始移动的滑动距离 private Boolean isCanDrag = false;//是否可以移动 private Boolean isNeedCheckTopAndBottom;//是否需要考虑top和boottom出现白边 private Boolean isNeedCheckLeftAndRight;//是否需要考虑left和right出现白边 private GestureDetector gestureDetector;//手势监听 private ScaleGestureDetector scaleGestureDetector;//缩放手势监听 public ZoomImageView(Context context) { this(context, null); } public ZoomImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setScaleType(ScaleType.MATRIX);//设置缩放类型 matrix = new Matrix(); scaleGestureDetector = new ScaleGestureDetector(getContext(), this); setOnTouchListener(this); onTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();//获取系统的默认开始移动的滑动距离 /** * 处理双击图片放大和缩小 */ gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { float scale = getScale(); float eventX = e.getX(); float eventY = getY(); if (scale < midScale) { postDelayed(new AutoScaleRunnable(eventX, eventY, maxScale), 16); } else { postDelayed(new AutoScaleRunnable(eventX, eventY, initScale), 16); } return true; } }); } /** * 用线程来实现图片缓慢变大和缩小 */ public class AutoScaleRunnable implements Runnable { private float clickX; private float clickY; private float targetScale; private float scaleTo; private float scaleBig = 1.07f; private float scaleSmall = 0.93f; public AutoScaleRunnable(float clickX, float clickY, float targetScale) { this.clickX = clickX; this.clickY = clickY; this.targetScale = targetScale; if (getScale() < targetScale) { scaleTo = scaleBig; } if (getScale() > targetScale) { scaleTo = scaleSmall; } } @Override public void run() { matrix.postScale(scaleTo, scaleTo, clickX, clickY); setImageMatrix(matrix); checkBorderWhenScale(); float currentScale = getScale(); if ((currentScale < targetScale && scaleTo > 1.0f) || (currentScale > targetScale && scaleTo < 1.0f)) { postDelayed(this, 16); } else { matrix.postScale(targetScale / currentScale, targetScale / currentScale, clickX, clickY); setImageMatrix(matrix); checkBorderWhenScale(); } } } /** * 注册 GlobalLayoutListener监听事件 */ @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewTreeObserver().addOnGlobalLayoutListener(this); } /** * 移除监听事件 */ @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeGlobalOnLayoutListener(this); } /** * 把图片定位到屏幕中央,并进行初始化缩放适应屏幕 */ @Override public void onGlobalLayout() { if (!first) { int with = getWidth(); int height = getHeight(); Drawable drawable = getDrawable(); if (drawable == null) return; int draWith = drawable.getIntrinsicWidth(); int draHeight = drawable.getIntrinsicHeight(); if (draWith > with && draHeight < height) { initScale = with * 1.0f / draWith; } if ((draWith > with && draHeight > height) || (draWith < with && draHeight < height)) { initScale = Math.min(with * 1.0f / draWith, height * 1.0f / draHeight); } if (draWith < with && draHeight > height) { // initScale = height * 1.0f / draHeight; initScale = getWidth() * 1.0f / draHeight; } maxScale = 4f * initScale; midScale = 2f * initScale; float dx = with / 2.0f - draWith / 2.0f; float dy = height / 2.0f - draHeight / 2.0f; matrix.postTranslate(dx, dy); matrix.postScale(initScale, initScale, with / 2.0f, height / 2.0f); this.setImageMatrix(matrix); first = true; } } /** * 获得缩放图片中图片的缩放值 * * @return */ public float getScale() { float values[] = new float[9]; matrix.getValues(values); return values[Matrix.MSCALE_X]; } /** * 获的缩放中图片的边界信息; * * @return */ private RectF getDrawableInfo() { Drawable drawable = getDrawable(); if (drawable == null) return null; int draWith = drawable.getIntrinsicWidth(); int draHeight = drawable.getIntrinsicHeight(); RectF rectF = new RectF(); rectF.set(0, 0, draWith, draHeight); matrix.mapRect(rectF);//why return rectF; } /** * 处理多触点缩放 * @param detector * @return */ @Override public boolean onScale(ScaleGestureDetector detector) { float scale = getScale(); float scaleFactor = detector.getScaleFactor(); if (getDrawable() == null) return true; if ((scale < maxScale && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) { if (scale * scaleFactor > maxScale) { scaleFactor = maxScale / scale; } if (scale * scaleFactor < initScale) { scaleFactor = initScale / scale; } matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); setImageMatrix(matrix); checkBorderWhenScale(); } return true;//why } /** * 缩放中边缘控制,防止边缘出现白边 */ private void checkBorderWhenScale() { RectF draRectF = getDrawableInfo(); if (draRectF == null) return; int with = getWidth(); int height = getHeight(); float dx = 0; float dy = 0; if (draRectF.width() >= with) { if (draRectF.left > 0) { dx = -draRectF.left; } if (draRectF.right < with) { dx = with - draRectF.right; } } if (draRectF.height() >= height) { if (draRectF.top > 0) { dy = -draRectF.top; } if (draRectF.bottom < height) { dy = height - draRectF.bottom; } } if (draRectF.height() < height) { dy = (height / 2.0f - draRectF.bottom + draRectF.height() / 2.0f); } if (draRectF.width() < with) { dx = (with / 2.0f - draRectF.right + draRectF.width() / 2.0f); } matrix.postTranslate(dx, dy); setImageMatrix(matrix); } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { return true;//why } @Override public void onScaleEnd(ScaleGestureDetector detector) { } /** * 处理touch事件 * @param v * @param event * @return */ @Override public boolean onTouch(View v, MotionEvent event) { if (gestureDetector.onTouchEvent(event))//传入touch事件给GestureDetector return true; scaleGestureDetector.onTouchEvent(event);//传入touch事件给scaleGestureDetector int touchPointCount = event.getPointerCount(); float x = 0; float y = 0; for (int i = 0; i < touchPointCount; i++) { x += event.getX(i); y += event.getY(i); } float centerX = x / touchPointCount; float centerY = y / touchPointCount; if (lastTouchPointCount != touchPointCount) { isCanDrag = false; lastX = centerX; lastY = centerY; } lastTouchPointCount = touchPointCount; RectF rectF = getDrawableInfo(); switch (event.getAction()) { // case MotionEvent.ACTION_DOWN: // if (rectF != null && (rectF.height() > getHeight() || rectF.width() > getWidth())) { // getParent().requestDisallowInterceptTouchEvent(true);//阻止父布局(viewpager)拦截事件 // } // break; case MotionEvent.ACTION_MOVE: // // if (rectF != null && (rectF.height() > getHeight() || rectF.width() > getWidth())) { // getParent().requestDisallowInterceptTouchEvent(true); // } float dx = centerX - lastX; float dy = centerY - lastY; if (!isCanDrag) { isCanDrag = isMoveAction(dx, dy); } if (isCanDrag) { isNeedCheckLeftAndRight = true; isNeedCheckTopAndBottom = true; RectF drawRecF = getDrawableInfo(); if (drawRecF != null) { if (drawRecF.width() < getWidth()) { isNeedCheckLeftAndRight = false; dx = 0; } if (drawRecF.height() < getHeight()) { dy = 0; isNeedCheckTopAndBottom = false; } matrix.postTranslate(dx, dy); setImageMatrix(matrix); checkBorderWhenTraslate(); } } lastX = centerX; lastY = centerY; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: lastTouchPointCount = 0; break; default: break; } return true; } /** * 保证触点缩放后平移不出现白边 */ public void checkBorderWhenTraslate() { RectF rectF2 = getDrawableInfo(); float dx = 0; float dy = 0; if (rectF2 == null) return; if (rectF2.right < getWidth() && isNeedCheckLeftAndRight) { dx = getWidth() - rectF2.right; } if (rectF2.left > 0 && isNeedCheckLeftAndRight) { dx = -rectF2.left; } if (rectF2.top > 0 && isNeedCheckTopAndBottom) { dy = -rectF2.top; } if (rectF2.bottom < getHeight() && isNeedCheckTopAndBottom) { dy = getHeight() - rectF2.bottom; } matrix.postTranslate(dx, dy); setImageMatrix(matrix); } /** * 判断是否可以移动 * * @param dx * @param dy * @return */ private boolean isMoveAction(float dx, float dy) { return Math.sqrt(dx * dx + dy * dy) > onTouchSlop; } }