在viewPager中双指缩放图片,双击缩放图片,单指拖拽图片,
我们就把这个问题叫做图片查看器吧,它的主要功能有:
1、双击缩放图片。
2、 双指缩放图片。
3、单指拖拽图片。
为此这个图片查看器需要考虑以下的技术点:
一、双击缩放图片:
1、如果图片高度比屏幕的高度小得多,那么就将图片放大到高度与屏幕高度相等,否则就放大一个特定的倍数。
2、如何判断是否到达这个倍数来停止缩放。
3、判断完且停止放大后,图片可能已经超出了这个倍数需要的大小,如何回归到我们的目标大小。
4、判断完且停止缩小后,图片宽度可能已经小于屏幕宽度,在两边留下了空白,如何重置为原来的大小。
二、双指缩放图片:
1、双指缩放,放大一个特定的倍数停止。
2、如何判断是否到达这个倍数。
3、放大停止后,图片可能已经超出了这个倍数需要的大小,如何回归到我们的目标大小。
4、缩小停止后,图片宽度可能已经小于屏幕宽度,在两边留下了空白,如何重置为原来的大小。
三、单指拖拽:
1、当图片宽度小于或等于屏幕宽度的时候,禁止左右移动,当图片的高度小于屏幕高度的时候,禁止上下移动。
2、移动图片时,如果图片的一边已经与屏幕之间有了空白,松手后恢复,让图片的这一边与屏幕边界重合。
四、
如何判断是双击,还是多指触控,还是单指。
五、
如何解决与viewPager的滑动冲突,当图片已经滑动到尽头无法滑动时,此时viewPager应该拦截事件。
我们逐一来解决:
public class MyImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,View.OnTouchListener {
public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); super.setScaleType(ScaleType.MATRIX); setOnTouchListener(this); /** * 双击实现图片放大缩小 */ mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { changeViewSize(e); return true; } }); }
在这里缩放图片是用matrix,因此首先要设置scaleType为matrix。
用手势判断双击行为。不要忘了在onTouch里面加上
if (mGestureDetector.onTouchEvent(event)) return true;
判断单指与多指触控,则在onTouch里面判断,要用 event.getAction() & MotionEvent.ACTION_MASK来判断。
//多指触控模式,单指,双指 private int mode; private final static int SINGLE_TOUCH = 1; //单指 private final static int DOUBLE_TOUCH = 2; //双指
@Override public boolean onTouch(View view, MotionEvent event) { rectF = getMatrixRectF(); if (mGestureDetector.onTouchEvent(event)) return true; switch (event.getAction() & event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mode = SINGLE_TOUCH; break; case MotionEvent.ACTION_MOVE: if (mode >= DOUBLE_TOUCH) //双指缩放 { } if (mode == SINGLE_TOUCH) //单指拖拽 { } break; case MotionEvent.ACTION_POINTER_DOWN: mode += 1;break; case MotionEvent.ACTION_POINTER_UP: mode -= 1; break; case MotionEvent.ACTION_UP: mode = 0; break; //在ACTION_MOVE中,事件被拦截了之后,有时候ACTION_UP无法触发,所以加上了ACTION_CANCEL case MotionEvent.ACTION_CANCEL: mode = 0; break; default: break; } return true; }
有如下事件使我们要用到的:
- MotionEvent.ACTION_DOWN:在第一个点被按下时触发
- MotionEvent.ACTION_UP:当屏幕上唯一的点被放开时触发
- MotionEvent.ACTION_POINTER_DOWN:当屏幕上已经有一个点被按住,此时再按下其他点时触发。
- MotionEvent.ACTION_POINTER_UP:当屏幕上有多个点被按住,松开其中一个点时触发(即非最后一个点被放开时)。
- MotionEvent.ACTION_MOVE:当有点在屏幕上移动时触发。值得注意的是,由于它的灵敏度很高,而我们的手指又不可能完全静止(即使我们感觉不到移动,但其实我们的手指也在不停地抖动),所以实际的情况是,基本上只要有点在屏幕上,此事件就会一直不停地被触发。
在ACTION_MOVE中通过mode的大小来判断是单指还是双指。
不过有一个令人伤心的事情,Android自己有一个bug。经过测试发现双指交换触碰图片的时候,程序会闪退,出现异常:pointIndex out of range。这是Android自己的bug。个人觉得最好得解决方法是自定义一个viewPager,然后在里面重写:onTouchEvent,onInterceptTouchEvent,然后捕获异常。
@Override public boolean onTouchEvent(MotionEvent ev) { try { return super.onTouchEvent(ev); } catch (IllegalArgumentException ex) { ex.printStackTrace(); } return false; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { try { return super.onInterceptTouchEvent(ev); } catch (IllegalArgumentException ex) { ex.printStackTrace(); } return false; }
这样程序就不会闪退了。
我们来看看双击放大的的代码:
/** * 双击缩放图片 */ private void changeViewSize(MotionEvent e) { //获取双击的坐标 final float x = e.getX(); final float y = e.getY(); //如果此时还在缩放那就直接返回 if (animator != null && animator.isRunning()) return; //判断是处于放大还是缩小的状态 if (!isZoomChanged()) { animator = ValueAnimator.o