效果图:

现在app中,图片预览功能肯定是少不了的,用户基本已经形成条件反射,看到小图,点击看大图,看到大图两个手指开始进行放大,放大后,开始移动到指定部位~~~

想要做到图片支持多点触控,自由的进行缩放、平移,需要了解几个知识点:Matrix , GestureDetector , ScaleGestureDetector 以及事件分发机制

1、Matrix

参考:http://geek.csdn.net/news/detail/89873   http://blog.csdn.net/flash129/article/details/8234599  http://blog.csdn.net/cquwentao/article/details/51445269

矩阵,看深入了都是3维矩阵的乘啊什么的,怪麻烦的~~

其实这么了解下就行了:

Matrix

数据结构:3维矩阵;

内部存储:new Float[9] ; 内部就是个一维数组,内部9个元素;可以进行setValues(float[] values)进行初始化

每个元素代表的意思

{  MSCALE_X, MSKEW_X, MTRANS_X,    MSKEW_Y, MSCALE_Y, MTRANS_Y,    MPERSP_0, MPERSP_1, MPERSP_2
};   

字面上,应该能看出来哪个代表x方向缩放,哪个代表垂直方向的偏移量吧~~有不认识的3个,没事,请无视。

操作

比如你想要设置matrix的偏移量为200,100

你可以这么写:

    Matrix transMatrix = new Matrix();  float[] values = new float[] { 1.0, 0, 200, 0, 1.0, 100, 0, 0, 1.0 };  transMatrix.setValues(values);  

如何获取值

当然了,我们对一个Matrix进行了各种操作,一会postScale,一会postTranslate;那么现在如何获得当前的缩放比例:
前面说setValues可以初始化,那么getValues就能拿到当前矩阵的值,拿到的是个一维数组,9个元素;再通过下标取对应值就可以。

比如我想知道现在x方向缩放比例:

    public final float getScale()  {  scaleMatrix.getValues(matrixValues);  return matrixValues[Matrix.MSCALE_X];  }  

好了,知道这些就够了~~

2、GestureDetector

参考:http://blog.csdn.net/xyz_lmn/article/details/16826669  http://blog.csdn.net/hpk1994/article/details/51224228

嗯,自己看API,能够捕捉到长按、双击什么的;用法会在例子中

3、ScaleGestureDetector

参考:http://blog.csdn.net/u010410408/article/details/39577399 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0211/2467.html

http://blog.csdn.net/true100/article/details/51141496

嗯,有点像继承来的,其实不是的,独立的一个类~用于检测缩放的手势~~~用法会在例子中

4、完整代码:

public class ZoomImageView extends ImageView implements OnScaleGestureListener, OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {private static final String TAG = ZoomImageView.class.getSimpleName();public static final float SCALE_MAX = 3.0f;private static final float SCALE_MID = 1.5f;/*** 初始化时的缩放比例,如果图片宽或高大于屏幕,此值将小于0*/private float initScale = 1.0f;private boolean once = true;/*** 用于存放矩阵的9个值*/private final float[] matrixValues = new float[9];/*** 缩放的手势检测*/private ScaleGestureDetector mScaleGestureDetector = null;private final Matrix mScaleMatrix = new Matrix();/*** 用于双击检测*/private GestureDetector mGestureDetector;private boolean isAutoScale;private int mTouchSlop;private float mLastX;private float mLastY;private boolean isCanDrag;private int lastPointerCount;private boolean isCheckTopAndBottom = true;private boolean isCheckLeftAndRight = true;public ZoomImageView(Context context) {this(context, null);}public ZoomImageView(Context context, AttributeSet attrs) {super(context, attrs);super.setScaleType(ScaleType.MATRIX);mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener() {@Overridepublic boolean onDoubleTap(MotionEvent e) {if (isAutoScale == true)return true;float x = e.getX();float y = e.getY();Log.e("DoubleTap", getScale() + " , " + initScale);if (getScale() < SCALE_MID) {//postDelayed(); 16 :多久实现一次的定时器操作ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MID, x, y), 16);isAutoScale = true;} /*else if (getScale() >= SCALE_MID  //连续双击放大 可放开&& getScale() < SCALE_MAX) {ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MAX, x, y), 16);isAutoScale = true;}*/ else {ZoomImageView.this.postDelayed(new AutoScaleRunnable(initScale, x, y), 16);isAutoScale = true;}return true;}});mScaleGestureDetector = new ScaleGestureDetector(context, this);this.setOnTouchListener(this);}/*** 自动缩放的任务* @author zhy*/private class AutoScaleRunnable implements Runnable {static final float BIGGER = 1.07f;static final float SMALLER = 0.93f;private float mTargetScale;private float tmpScale;/*** 缩放的中心*/private float x;private float y;/*** 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小* @param targetScale*/public AutoScaleRunnable(float targetScale, float x, float y) {this.mTargetScale = targetScale;this.x = x;this.y = y;if (getScale() < mTargetScale) {tmpScale = BIGGER;} else {tmpScale = SMALLER;}}@Overridepublic void run() {// 进行缩放mScaleMatrix.postScale(tmpScale, tmpScale, x, y);checkBorderAndCenterWhenScale();setImageMatrix(mScaleMatrix);final float currentScale = getScale();// 如果值在合法范围内,继续缩放if (((tmpScale > 1f) && (currentScale < mTargetScale)) || ((tmpScale < 1f) && (mTargetScale < currentScale))) {ZoomImageView.this.postDelayed(this, 16);} else {// 设置为目标的缩放比例final float deltaScale = mTargetScale / currentScale;mScaleMatrix.postScale(deltaScale, deltaScale, x, y);checkBorderAndCenterWhenScale();setImageMatrix(mScaleMatrix);isAutoScale = false;}}}/*** 对图片进行缩放的控制,首先进行缩放范围的判断,然后设置mScaleMatrix的scale值* @param detector* @return*/@SuppressLint("NewApi")@Overridepublic boolean onScale(ScaleGestureDetector detector) {float scale = getScale();float scaleFactor = detector.getScaleFactor();if (getDrawable() == null)return true;/*** 缩放的范围控制*/if ((scale < SCALE_MAX && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) {/*** 最大值最小值判断*/if (scaleFactor * scale < initScale) {scaleFactor = initScale / scale;}if (scaleFactor * scale > SCALE_MAX) {scaleFactor = SCALE_MAX / scale;}/*** 设置缩放比例*/mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());checkBorderAndCenterWhenScale();setImageMatrix(mScaleMatrix);}return true;}/*** 在缩放时,进行图片显示范围的控制*/private void checkBorderAndCenterWhenScale() {RectF rect = getMatrixRectF();float deltaX = 0;float deltaY = 0;int width = getWidth();int height = getHeight();// 如果宽或高大于屏幕,则控制范围if (rect.width() >= width) {if (rect.left > 0) {deltaX = -rect.left;}if (rect.right < width) {deltaX = width - rect.right;}}if (rect.height() >= height) {if (rect.top > 0) {deltaY = -rect.top;}if (rect.bottom < height) {deltaY = height - rect.bottom;}}// 如果宽或高小于屏幕,则让其居中if (rect.width() < width) {deltaX = width * 0.5f - rect.right + 0.5f * rect.width();}if (rect.height() < height) {deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();}Log.e(TAG, "deltaX = " + deltaX + " , deltaY = " + deltaY);mScaleMatrix.postTranslate(deltaX, deltaY);}/*** 根据当前图片的Matrix获得图片的范围* @return*/private RectF getMatrixRectF() {Matrix matrix = mScaleMatrix;RectF rect = new RectF();Drawable d = getDrawable();if (null != d) {rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());matrix.mapRect(rect);}return rect;}@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {}/*** 我们让OnTouchListener的MotionEvent交给ScaleGestureDetector进行处理* public boolean onTouch(View v, MotionEvent event){* return mScaleGestureDetector.onTouchEvent(event);* }*/@Overridepublic boolean onTouch(View v, MotionEvent event) {if (mGestureDetector.onTouchEvent(event))return true;mScaleGestureDetector.onTouchEvent(event);float x = 0, y = 0;// 拿到触摸点的个数final int pointerCount = event.getPointerCount();// 得到多个触摸点的x与y均值for (int i = 0; i < pointerCount; i++) {x += event.getX(i);y += event.getY(i);}x = x / pointerCount;y = y / pointerCount;/*** 每当触摸点发生变化时,重置mLasX , mLastY*/if (pointerCount != lastPointerCount) {isCanDrag = false;mLastX = x;mLastY = y;}lastPointerCount = pointerCount;RectF rectF = getMatrixRectF();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (rectF.width() > getWidth() || rectF.height() > getHeight()) {getParent().requestDisallowInterceptTouchEvent(true);}break;case MotionEvent.ACTION_MOVE:if (rectF.width() > getWidth() || rectF.height() > getHeight()) {getParent().requestDisallowInterceptTouchEvent(true);}Log.e(TAG, "ACTION_MOVE");float dx = x - mLastX;float dy = y - mLastY;if (!isCanDrag) {isCanDrag = isCanDrag(dx, dy);}if (isCanDrag) {if (getDrawable() != null) {// if (getMatrixRectF().left == 0 && dx > 0)// {// getParent().requestDisallowInterceptTouchEvent(false);// }//// if (getMatrixRectF().right == getWidth() && dx < 0)// {// getParent().requestDisallowInterceptTouchEvent(false);// }isCheckLeftAndRight = isCheckTopAndBottom = true;// 如果宽度小于屏幕宽度,则禁止左右移动if (rectF.width() < getWidth()) {dx = 0;isCheckLeftAndRight = false;}// 如果高度小雨屏幕高度,则禁止上下移动if (rectF.height() < getHeight()) {dy = 0;isCheckTopAndBottom = false;}//设置偏移量mScaleMatrix.postTranslate(dx, dy);//再次校验checkMatrixBounds();setImageMatrix(mScaleMatrix);}}mLastX = x;mLastY = y;break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_UP");lastPointerCount = 0;break;}return true;}/*** 获得当前的缩放比例* @return*/public final float getScale() {mScaleMatrix.getValues(matrixValues);return matrixValues[Matrix.MSCALE_X];}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();getViewTreeObserver().addOnGlobalLayoutListener(this);}@SuppressWarnings("deprecation")@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();getViewTreeObserver().removeGlobalOnLayoutListener(this);}/*** 根据图片的宽和高以及屏幕的宽和高,对图片进行缩放以及移动至屏幕的中心。* 如果图片很小,那就正常显示,不放大了~*/@Overridepublic void onGlobalLayout() {if (once) {Drawable d = getDrawable();if (d == null)return;Log.e(TAG, d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());int width = getWidth();int height = getHeight();// 拿到图片的宽和高int dw = d.getIntrinsicWidth();int dh = d.getIntrinsicHeight();float scale = 1.0f;// 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高if (dw > width && dh <= height) {scale = width * 1.0f / dw;}if (dh > height && dw <= width) {scale = height * 1.0f / dh;}// 如果宽和高都大于屏幕,则让其按按比例适应屏幕大小if (dw > width && dh > height) {scale = Math.min(width * 1.0f / dw, height * 1.0f / dh);}initScale = scale;Log.e(TAG, "initScale = " + initScale);mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2);mScaleMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2);// 图片移动至屏幕中心setImageMatrix(mScaleMatrix);once = false;}}/*** 移动时,进行边界判断,主要判断宽或高大于屏幕的*/private void checkMatrixBounds() {RectF rect = getMatrixRectF();float deltaX = 0, deltaY = 0;final float viewWidth = getWidth();final float viewHeight = getHeight();// 判断移动或缩放后,图片显示是否超出屏幕边界if (rect.top > 0 && isCheckTopAndBottom) {deltaY = -rect.top;}if (rect.bottom < viewHeight && isCheckTopAndBottom) {deltaY = viewHeight - rect.bottom;}if (rect.left > 0 && isCheckLeftAndRight) {deltaX = -rect.left;}if (rect.right < viewWidth && isCheckLeftAndRight) {deltaX = viewWidth - rect.right;}mScaleMatrix.postTranslate(deltaX, deltaY);}/*** 是否是推动行为** @param dx* @param dy* @return*/private boolean isCanDrag(float dx, float dy) {return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;}}

1、我们在onGlobalLayout的回调中,根据图片的宽和高以及屏幕的宽和高,对图片进行缩放以及移动至屏幕的中心。如果图片很小,那就正常显示,不放大了~

2、我们让OnTouchListener的MotionEvent交给ScaleGestureDetector进行处理

    @Override  public boolean onTouch(View v, MotionEvent event)  {  return mScaleGestureDetector.onTouchEvent(event);  }  

3、在onScale的回调中对图片进行缩放的控制,首先进行缩放范围的判断,然后设置mScaleMatrix的scale值

现在的效果:

1、小于屏幕的宽和高


2、大于屏幕的宽和高

可是,可是,存在问题:

1、缩放的中心点,我们设置是固定的,屏幕中间

2、放大后,无法移动~

下面,我们先解决缩放的中心点问题,不能一直按屏幕中心么,像我这样的,我比较关注妹子的眼睛,我要放大那一块~~~

2、设置缩放中心

1、单纯的设置缩放中心

仅仅是设置中心很简单,直接修改下中心点 :

    /** * 设置缩放比例 */  mScaleMatrix.postScale(scaleFactor, scaleFactor,  detector.getFocusX(), detector.getFocusX());  setImageMatrix(mScaleMatrix);  

但是,随意的中心点放大、缩小,会导致图片的位置的变化,最终导致,图片宽高大于屏幕时,图片与屏幕间出现白边;图片小于屏幕,但是不居中。

2、控制缩放时图片显示的范围

所以我们在缩放的时候需要手动控制下范围:

    /** * 在缩放时,进行图片显示范围的控制 */  private void checkBorderAndCenterWhenScale()  {  RectF rect = getMatrixRectF();  float deltaX = 0;  float deltaY = 0;  int width = getWidth();  int height = getHeight();  // 如果宽或高大于屏幕,则控制范围  if (rect.width() >= width)  {  if (rect.left > 0)  {  deltaX = -rect.left;  }  if (rect.right < width)  {  deltaX = width - rect.right;  }  }  if (rect.height() >= height)  {  if (rect.top > 0)  {  deltaY = -rect.top;  }  if (rect.bottom < height)  {  deltaY = height - rect.bottom;  }  }  // 如果宽或高小于屏幕,则让其居中  if (rect.width() < width)  {  deltaX = width * 0.5f - rect.right + 0.5f * rect.width();  }  if (rect.height() < height)  {  deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();  }  Log.e(TAG, "deltaX = " + deltaX + " , deltaY = " + deltaY);  mScaleMatrix.postTranslate(deltaX, deltaY);  }  /** * 根据当前图片的Matrix获得图片的范围 *  * @return */  private RectF getMatrixRectF()  {  Matrix matrix = mScaleMatrix;  RectF rect = new RectF();  Drawable d = getDrawable();  if (null != d)  {  rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());  matrix.mapRect(rect);  }  return rect;  }  

在onScale里面记得调用:

/** * 设置缩放比例 */  mScaleMatrix.postScale(scaleFactor, scaleFactor,  detector.getFocusX(), detector.getFocusY());  checkBorderAndCenterWhenScale();  setImageMatrix(mScaleMatrix); 

这样就好了,可以自由的放大任何地方,并且不会出现边界出现白边,也能很好的让图片显示在屏幕中间(当图片宽或高小于屏幕);

下面介绍:多点触控时移动,双击变大,双击变小

1.自由的进行移动

我们在onTouchEvent里面,加上移动的代码,当然了,必须长或宽大于屏幕才可以移动~~~

    @Override  public boolean onTouch(View v, MotionEvent event)  {  mScaleGestureDetector.onTouchEvent(event);  float x = 0, y = 0;  // 拿到触摸点的个数  final int pointerCount = event.getPointerCount();  // 得到多个触摸点的x与y均值  for (int i = 0; i < pointerCount; i++)  {  x += event.getX(i);  y += event.getY(i);  }  x = x / pointerCount;  y = y / pointerCount;  /** * 每当触摸点发生变化时,重置mLasX , mLastY  */  if (pointerCount != lastPointerCount)  {  isCanDrag = false;  mLastX = x;  mLastY = y;  }  lastPointerCount = pointerCount;  switch (event.getAction())  {  case MotionEvent.ACTION_MOVE:  Log.e(TAG, "ACTION_MOVE");  float dx = x - mLastX;  float dy = y - mLastY;  if (!isCanDrag)  {  isCanDrag = isCanDrag(dx, dy);  }  if (isCanDrag)  {  RectF rectF = getMatrixRectF();  if (getDrawable() != null)  {  isCheckLeftAndRight = isCheckTopAndBottom = true;  // 如果宽度小于屏幕宽度,则禁止左右移动  if (rectF.width() < getWidth())  {  dx = 0;  isCheckLeftAndRight = false;  }  // 如果高度小雨屏幕高度,则禁止上下移动  if (rectF.height() < getHeight())  {  dy = 0;  isCheckTopAndBottom = false;  }  mScaleMatrix.postTranslate(dx, dy);  checkMatrixBounds();  setImageMatrix(mScaleMatrix);  }  }  mLastX = x;  mLastY = y;  break;  case MotionEvent.ACTION_UP:  case MotionEvent.ACTION_CANCEL:  Log.e(TAG, "ACTION_UP");  lastPointerCount = 0;  break;  }  return true;  }  

首先我们拿到触摸点的数量,然后求出多个触摸点的平均值,设置给我们的mLastX , mLastY , 然后在移动的时候,得到dx ,dy 进行范围检查以后,调用mScaleMatrix.postTranslate进行设置偏移量,当然了,设置完成以后,还需要再次校验一下,不能把图片移动的与屏幕边界出现白边,校验完成后,调用setImageMatrix.

这里:需要注意一下,我们没有复写ACTION_DOWM,是因为,ACTION_DOWN在多点触控的情况下,只要有一个手指按下状态,其他手指按下不会再次触发ACTION_DOWN,但是多个手指以后,触摸点的平均值会发生很大变化,所以我们没有用到ACTION_DOWN。每当触摸点的数量变化,我们就会跟新当前的mLastX,mLastY.

下面是上面用到的两个私有方法,一个用于检查边界,一个用于判断是否是拖动的操作:

    /** * 移动时,进行边界判断,主要判断宽或高大于屏幕的 */  private void checkMatrixBounds()  {  RectF rect = getMatrixRectF();  float deltaX = 0, deltaY = 0;  final float viewWidth = getWidth();  final float viewHeight = getHeight();  // 判断移动或缩放后,图片显示是否超出屏幕边界  if (rect.top > 0 && isCheckTopAndBottom)  {  deltaY = -rect.top;  }  if (rect.bottom < viewHeight && isCheckTopAndBottom)  {  deltaY = viewHeight - rect.bottom;  }  if (rect.left > 0 && isCheckLeftAndRight)  {  deltaX = -rect.left;  }  if (rect.right < viewWidth && isCheckLeftAndRight)  {  deltaX = viewWidth - rect.right;  }  mScaleMatrix.postTranslate(deltaX, deltaY);  }  /** * 是否是推动行为 *  * @param dx * @param dy * @return */  private boolean isCanDrag(float dx, float dy)  {  return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;  }  

这样,我们就可以快乐的放大、缩小加移动了~~~

2.双击放大缩小

谈到双击事件,我们的GestureDetector终于要登场了,这哥们可以捕获双击事件~~

1.GestureDetector的使用:

因为GestureDetector设置监听器的话,方法一大串,而我们只需要onDoubleTap这个回调,所以我们准备使用它的一个内部类SimpleOnGestureListener,对接口的其他方法实现了空实现。

不过还有几个问题需要讨论下,才能开始我们的代码:

1、我们双击尺寸如何变化?

我是这样的,根据当前的缩放值,如果是小于2的,我们双击直接到变为原图的2倍;如果是2,4之间的,我们双击直接为原图的4倍;其他状态也就是4倍,双击后还原到最初的尺寸。

如果你觉得这样不合适,可以根据自己的爱好调整。

2、我们双击变化,需要一个动画~~比如我们上例的演示图,图片很大,全屏显示的时候initScale=0.5左后,如果双击后变为2,也就是瞬间大了四倍,没有一个过渡的效果的话,给用户的感觉会特别差。所以,我们准备使用postDelay执行一个Runnable,Runnable中再次根据的当然的缩放值继续执行。

首先我们在构造方法中,完成对GestureDetector的初始化,以及设置onDoubleTap监听

    public ZoomImageView(Context context, AttributeSet attrs)  {  super(context, attrs);  mScaleGestureDetector = new ScaleGestureDetector(context, this);  mGestureDetector = new GestureDetector(context,  new SimpleOnGestureListener()  {  @Override  public boolean onDoubleTap(MotionEvent e)  {  if (isAutoScale == true)  return true;  float x = e.getX();  float y = e.getY();  Log.e("DoubleTap", getScale() + " , " + initScale);  if (getScale() < SCALE_MID)  {  ZoomImageView.this.postDelayed(  new AutoScaleRunnable(SCALE_MID, x, y), 16);  isAutoScale = true;  } else if (getScale() >= SCALE_MID  && getScale() < SCALE_MAX)  {  ZoomImageView.this.postDelayed(  new AutoScaleRunnable(SCALE_MAX, x, y), 16);  isAutoScale = true;  } else  {  ZoomImageView.this.postDelayed(  new AutoScaleRunnable(initScale, x, y), 16);  isAutoScale = true;  }  return true;  }  });  mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  super.setScaleType(ScaleType.MATRIX);  this.setOnTouchListener(this);  }  

1、当双击的时候,首先判断是否正在自动缩放,如果在,直接retrun ;

2、然后就进入了我们的if,如果当然是scale小于2,则通过view.发送一个Runnable进行执行;其他类似;

下面看我们的Runnable的代码:

    /** * 自动缩放的任务 */  private class AutoScaleRunnable implements Runnable  {  static final float BIGGER = 1.07f;  static final float SMALLER = 0.93f;  private float mTargetScale;  private float tmpScale;  /** * 缩放的中心 */  private float x;  private float y;  /** * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小 *  * @param targetScale */  public AutoScaleRunnable(float targetScale, float x, float y)  {  this.mTargetScale = targetScale;  this.x = x;  this.y = y;  if (getScale() < mTargetScale)  {  tmpScale = BIGGER;  } else  {  tmpScale = SMALLER;  }  }  @Override  public void run()  {  // 进行缩放  mScaleMatrix.postScale(tmpScale, tmpScale, x, y);  checkBorderAndCenterWhenScale();  setImageMatrix(mScaleMatrix);  final float currentScale = getScale();  //如果值在合法范围内,继续缩放  if (((tmpScale > 1f) && (currentScale < mTargetScale))  || ((tmpScale < 1f) && (mTargetScale < currentScale)))  {  ZoomImageView.this.postDelayed(this, 16);  } else//设置为目标的缩放比例  {  final float deltaScale = mTargetScale / currentScale;  mScaleMatrix.postScale(deltaScale, deltaScale, x, y);  checkBorderAndCenterWhenScale();  setImageMatrix(mScaleMatrix);  isAutoScale = false;  }  }  }  

代码写完了,我们依然需要把我们的event传给它,依然是在onTouch方法:

    @Override  public boolean onTouch(View v, MotionEvent event)  {  if (mGestureDetector.onTouchEvent(event))  return true;

连续双击放大,感觉不爽,代码已经上传,我就不重传了,如果你也觉得不爽,可以自行注释。

//                      else if (getScale() >= SCALE_MID
//                              && getScale() < SCALE_MAX)
//                      {
//                          ZoomImageView.this.postDelayed(
//                                  new AutoScaleRunnable(SCALE_MAX, x, y), 16);
//                          isAutoScale = true;
//                      }  

源码:http://download.csdn.net/download/lijinweii/9957495

Android 图片随着手势缩放,平移,并且支持多点触控相关推荐

  1. Android 自定义密码键盘组件,支持多点触控

    前言 现在对于前端APP的安全要求越来越高,所以很多APP都开发了自己的数字键盘,这么做对于安全性的提升个人总结有如下几点: 防止第三方键盘出现BUG,泄露用户支付密码. 自定义键盘可以根据自己的算法 ...

  2. Android笔记:触摸事件的分析与总结----多点触控

       其他相关博文:    Android笔记:触摸事件的分析与总结----MotionEvent对象    Android笔记:触摸事件的分析与总结----TouchEvent处理机制     An ...

  3. linux多点触摸屏驱动程序,Linux系统实现支持多点触控操作[视频]

    虽然大多数人目前还不会购买拥有触控屏的设备,不过在Windows 7的大力推动下,触控操作已经开始流行了起来.然而Linux目前却无法支持这一功能,这让很多用户十分郁闷,不过来自ENAC Intera ...

  4. android 多个手指同时点击,处理多点触控手势  |  Android 开发者  |  Android Developers...

    多点触控手势是指多个指针(手指)同时轻触屏幕.这节课介绍了如何检测涉及多个指针的手势. 请参阅以下相关资源: 跟踪多个指针 当多个指针同时轻触屏幕时,系统会生成以下触摸事件: 您可以通过每个指针的索引 ...

  5. android 图片 居中 手势缩放 设置缩放比例,ImageView通过matrix实现手势缩放

    关于ImageView的手势缩放,有很多种方法,绝大多数开源自定义缩放都是修改了ondraw函数来实现的.但是ImageView本身有scaleType属性,通过设置android:scaleType ...

  6. Android App接管手势处理TouchEvnet中单点触摸和多点触控的讲解及实战(附源码 超简单实用)

    运行有问题或需要源码请点赞关注收藏后评论区留言~~~ 一.单点触摸 dispatchTouchEvent onInterceptTouchEvent onTouchEvent三个方法的输入参数都是手势 ...

  7. Android多点触控详解

    本文转载自GcsSloop的 安卓自定义View进阶-多点触控详解 的文章 Android 多点触控详解,在前面的几篇文章中我们大致了解了 Android 中的事件处理流程和一些简单的处理方案,本次带 ...

  8. Android中的多点触控(装载)

    Android多点触控技术 1 简介 Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支 ...

  9. Android多点触控技术

    1 简介 Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouc ...

最新文章

  1. AI开发者们,2017年你们过得好吗?
  2. 从根因入手,更有效率,效果也更好
  3. mysql 8.0 自定义函数_PHP+Mysql防止SQL注入的方法(life)
  4. 40 | 案例篇:网络请求延迟变大了,我该怎么办?
  5. 常见的权限访问控制模型
  6. 线程组之间的JMeter传递变量
  7. 华为云牵手同舟共济伙伴 持续发力构建云核心生态圈
  8. 每天进步一点点《ML - 逻辑回归》
  9. ADO.Net之SqlConnection、 Sqlcommand的应用(读书笔记1)
  10. 水晶報表:金額轉換大寫12/8
  11. 兰州大学2016年初试成绩基本要求
  12. bzoj 3262: 陌上花开(cdq分治)
  13. 【Magick++透明图层合并】
  14. php小小通讯录,小小通讯录
  15. 360大战QQ演义之一:一场腾讯可能连底裤都输掉的战争!
  16. 本悟法师:信仰,让孤独走开
  17. NCRE考试感想 三级信息安全(下)
  18. type是python保留字_Python保留字总结
  19. 北航软件测评中心 招聘FPGA测试工程师
  20. 2017 ACM Arabella Collegiate Programming Contest A. Sherlock Bones GYM101350A

热门文章

  1. python借助jieba包对单独test和txt文档进行中文分词
  2. Ubuntu进入桌面后,左侧菜单栏和窗口菜单栏不见了的解决方法
  3. 一周消息树:推低端iPhone,将会是苹果必然之举
  4. win10的怎么调计算机亮度,win10电脑亮度怎么调
  5. (附源码)SSM网络故障报修系统 毕业设计 291146
  6. firefox装在linux_在 Linux 中安装 Firefox
  7. 谷歌2022学术指标出炉!Nature继续霸榜,CVPR第4,计算机5顶会入Top20
  8. 美国互联网影视业的盈利模式
  9. 系统分析与设计期末课程总结
  10. smbpasswd命令常用选项