1. 程式人生 > >打造自己的可雙擊放大、多指縮放、放大等功能的ImageView

打造自己的可雙擊放大、多指縮放、放大等功能的ImageView

不多說上程式碼

package com.sdp.panda.myviewapp.view;

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 80926 on 2016/11/23. */ public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener, ScaleGestureDetector.OnScaleGestureListener
, View.OnTouchListener {
//多指的放大與縮小的成員變數 private boolean mOnce; private float mInitScale;//初始化的最小縮放值 private float mMidScale;//雙擊的縮放值 private float mMaxScale;//放大的最大值 private Matrix mMatrix; private ScaleGestureDetector mScaleGestureDetector;//手勢 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~````
//自由移動的成員變數 private int mLastPointerCount;//最後多指的數目 private float mLastX; private float mLastY; private int mTouchSlop; private boolean isCanDrag;//可以拖拽 private boolean isMoveTopAndBottom;//是否可以上移下移 private boolean isMoveLeftAndRight; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``~~~~~~~~~~~~~~~~ //雙擊的成員變數 private GestureDetector mGestureDetector;//雙擊的類 private boolean isAutoScale;//避免使用者一直雙擊 public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public ZoomImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ZoomImageView(Context context) { this(context, null);//一個引數的引用兩個引數的 } private void init(Context context) { mMatrix = new Matrix(); // setScaleType(ScaleType.MATRIX); mScaleGestureDetector = new ScaleGestureDetector(context, this); setOnTouchListener(this); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();//是可以move的值 mGestureDetector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onDoubleTap(MotionEvent e) { if (isAutoScale){ return true; } float x = e.getX(); float y = e.getY(); if (getScale()<mMidScale){ // mMatrix.postScale(mMidScale/getScale(),mMidScale/getScale(),x,y); // setImageMatrix(mMatrix); postDelayed(new AutoScaleRunnable(mMidScale,x,y),15); isAutoScale = true; }else { // mMatrix.postScale(mInitScale/getScale(),mInitScale/getScale(),x,y); // setImageMatrix(mMatrix); postDelayed(new AutoScaleRunnable(mInitScale,x,y),15); isAutoScale = true; } return true; } }); } @Override public void onGlobalLayout() { if (!mOnce) { int width = getWidth();//控制元件的寬和高 int height = getHeight(); Drawable drawable = getDrawable(); if (drawable == null) { return; } float scaleSize = 0;//縮放尺寸 int dWidth = drawable.getIntrinsicWidth();//圖片的寬和高 int dHeight = drawable.getIntrinsicHeight(); if (dWidth > width && dHeight < height) { scaleSize = width * 1.0f / dWidth;//防止為0,提前轉換為float型別 } if (dHeight > height && dWidth < width) { scaleSize = height * 1.0f / dHeight; } if (dWidth > width && dHeight > height || dWidth < width && dHeight < height) { scaleSize = Math.min(height * 1.0f / dHeight, width * 1.0f / dWidth); } mInitScale = scaleSize; mMidScale = mInitScale * 2;//雙擊的初始化的兩倍 mMaxScale = mInitScale * 4;//最大是初始化的4倍 //將圖片移動至螢幕的中心 int centerX = (width - dWidth) / 2; int centerY = (height - dHeight) / 2; mMatrix.postTranslate(centerX, centerY); mMatrix.postScale(mInitScale, mInitScale, width / 2, height / 2); setImageMatrix(mMatrix);//矩陣 長度為9的一元陣列 mOnce = true; } } @Override protected void onAttachedToWindow() {//實現window的時候天劍 super.onAttachedToWindow(); getViewTreeObserver().addOnGlobalLayoutListener(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeOnGlobalLayoutListener(this); } //獲取當前圖片的縮放值 private float getScale() { float[] values = new float[9]; mMatrix.getValues(values); return values[Matrix.MSCALE_X]; } @Override public boolean onScale(ScaleGestureDetector detector) {//縮放中 float scaleFactor = detector.getScaleFactor();//獲取縮放值 //縮放區間 initScale~maxScale; float scale = getScale(); if (getDrawable() == null) { return true; } if (scale < mMaxScale && scaleFactor > 1.0f || scale > mInitScale && scaleFactor < 1.0f) { if (scale * scaleFactor < mInitScale) { scaleFactor = mInitScale / scale; } if (scale * scaleFactor > mMaxScale) { scaleFactor = mMaxScale / scale; } mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); setImageViewInCenterWhenCheck(); setImageMatrix(mMatrix); } return true; } //獲取可以得到圖片的四個角的矩形 private RectF getMatrixRectF() { Matrix mMatrix = this.mMatrix; RectF rectF = new RectF(); Drawable d = getDrawable(); if (d != null) { rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); mMatrix.mapRect(rectF); } return rectF; } //設定圖片在縮放最後中間 private void setImageViewInCenterWhenCheck() { RectF matrixRectF = getMatrixRectF(); float postX = 0; float postY = 0; int width = getWidth(); int height = getHeight(); if (matrixRectF.width() >= width) { if (matrixRectF.left > 0) { postX = -matrixRectF.left; } if (matrixRectF.right < width) { postX = width - matrixRectF.right; } } if (matrixRectF.height() >= height) { if (matrixRectF.top > 0) { postY = -matrixRectF.top; } if (matrixRectF.bottom < height) { postY = height - matrixRectF.bottom; } } //寬度和高度小於控制元件的寬和高的時候讓其居中 if (matrixRectF.width() < width) { postX = width / 2 - matrixRectF.right + matrixRectF.width() / 2; } if (matrixRectF.height() < height) { postY = height / 2 - matrixRectF.bottom + matrixRectF.height() / 2; } mMatrix.postTranslate(postX, postY); } @Override public boolean onScaleBegin(ScaleGestureDetector detector) {//開始 return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) {} @Override public boolean onTouch(View v, MotionEvent event) { if (mGestureDetector.onTouchEvent(event)){ return true; } mScaleGestureDetector.onTouchEvent(event); float x = 0; float y = 0; int pointerCount = event.getPointerCount(); for (int i = 0; i < pointerCount; i++) { x += event.getX(i); y += event.getY(i); } x /= pointerCount; y /= pointerCount; if (mLastPointerCount != pointerCount) { isCanDrag = false; mLastX = x; mLastY = y; } mLastPointerCount = pointerCount; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //解決與viewPager的衝突事件:加上0.01防止誤差 if (getMatrixRectF().width()>getWidth()+0.01||getMatrixRectF().height()>getHeight()+0.01){ getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_MOVE: if (getMatrixRectF().width()>getWidth()+0.01||getMatrixRectF().height()>getHeight()+0.01){ getParent().requestDisallowInterceptTouchEvent(true); } float dx = x - mLastX; float dy = y - mLastY;//移動量 if (!isCanDrag) { isCanDrag = isCanTouchMove(dx, dy); } if (isCanDrag) { RectF matrixRectF = getMatrixRectF(); if (getDrawable() != null) { isMoveLeftAndRight = isMoveTopAndBottom = true; if (matrixRectF.width() < getWidth()) {//如果圖片的寬和高小於控制元件的寬和高不允許移動 isMoveLeftAndRight = false; dx = 0; } if (matrixRectF.height() < getHeight()) { isMoveTopAndBottom = false; dy = 0; } mMatrix.postTranslate(dx, dy); WhenMoveCheck(); setImageMatrix(mMatrix); } } mLastX = x; mLastY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mLastPointerCount = 0; break; } return true; } //該方法是用於制約圖片移動的時候不會留白 private void WhenMoveCheck() { RectF matrixRectF = getMatrixRectF(); float dx = 0; float dy = 0; int width = getWidth(); int height = getHeight(); if (matrixRectF.top>0&&isMoveTopAndBottom){ dy = - matrixRectF.top; } if (matrixRectF.bottom<height&&isMoveTopAndBottom){ dy = height-matrixRectF.bottom; } if (matrixRectF.left>0&&isMoveLeftAndRight){ dx = -matrixRectF.left; } if (matrixRectF.right<width&& isMoveLeftAndRight){ dx = width-matrixRectF.right; } mMatrix.postTranslate(dx,dy); setImageMatrix(mMatrix); } private boolean isCanTouchMove(float dx, float dy) { return Math.sqrt(dx * dx + dy * dy) > mTouchSlop; } private class AutoScaleRunnable implements Runnable{ private float mTargetScale;//縮放的目標值 private float x; private float y;//中心點 private final float BIGGER = 1.05F; private final float SMALL = 0.95F; private float tmpScale; public AutoScaleRunnable(float targetScale,float x,float y){ this.mTargetScale = targetScale; this.x = x; this.y = y; if (getScale()<mTargetScale){ tmpScale = BIGGER; } if (getScale()>mTargetScale){ tmpScale = SMALL; } } @Override public void run() { mMatrix.postScale(tmpScale,tmpScale,x,y); setImageViewInCenterWhenCheck(); setImageMatrix(mMatrix); float currentScale = getScale(); if (tmpScale>1.0f&&currentScale <mTargetScale || tmpScale<1.0f && currentScale>mTargetScale){ postDelayed(this,15); }else {//設定目標值 float scale = mTargetScale/currentScale; mMatrix.postScale(scale,scale,x,y); setImageViewInCenterWhenCheck(); setImageMatrix(mMatrix); isAutoScale = false; } } } }

此自定義控制元件可以與viewPager等使用,但是需處理其衝突事件

因為在viewPager中如不處理就無法進行對放大的圖片進行點選移動的效果。。。
上述程式碼中:
  if (getMatrixRectF().width()>getWidth()+0.01
  ||getMatrixRectF().height()>getHeight()+0.01){
                getParent().requestDisallowInterceptTouchEvent(true);
            }
 正是處理這個衝突事件,只是先處理ImageView的放大縮小事件,最後可以進行滑動