其实在我们日常的编程中,对于缩放手势的使用并不是很经常,这一手势主要是用在图片浏览方面,比如下方例子。但是(敲重点),作为 Android 入门的基础来说,学习 ScaleGestureDetector 的使用,算是不得不过的一道坎,好在 ScaleGestureDetector 使用起来非常简单,就是源码分析上得花些功夫。
本文首先将简单的介绍下 ScaleGestureDetector 的使用,在重点给大家分析下源码(由于源码方面是我自己的理解,可能有偏差,希望各位大佬能在评论区指出,万分感谢~)
ScaleGestureDetector 使用ScaleGestureDetector 包括一个监听器,以及它所有方法的空实现:
名称 用途ScaleGestureDetector 缩放手势的监听器
SimpleOnScaleGestureListener 该监听器的空实现,在其中重写方法
ScaleGestureDetector 方法 名称 用途
onScaleBegin 当 >= 2 个手指碰触屏幕时调用,若返回 false 则忽略改事件调用
onScale 滑动(缩放)过程中调用,若成功处理,则用户返回 true,监听器继续记录下一个缩放等动作,若为 false 表明数据未处理,则监听器继续积累
onScaleEnd 全部手指离开屏幕,结束监听
通常情况下,手势监听会结合自定义 View 来讲,这里我给出一个最简单的使用,具体的使用实例,以后再结合自定义 View 讲讲。
private void iniScaleGestureListener(){ mListener = new ScaleGestureDetector.SimpleOnScaleGestureListener(){ @Override public boolean onScaleBegin(ScaleGestureDetector detector) { return super.onScaleBegin(detector); } @Override public boolean onScale(ScaleGestureDetector detector) { MyLog.d("X:" + detector.getFocusX()); MyLog.d("Y:" + detector.getFocusY()); MyLog.d("scale:" + detector.getScaleFactor()); return super.onScale(detector); } @Override public void onScaleEnd(ScaleGestureDetector detector) { super.onScaleEnd(detector); } }; detector = new ScaleGestureDetector(getContext(), mListener); } @Override public boolean onTouchEvent(MotionEvent event) { detector.onTouchEvent(event); return true; } ScaleGestureDetector 的使用ScaleGestureDetector 在具体项目的使用有点复杂,我打算过段时间结合自定义 View 写一篇用来总结,所以这篇我们就先了解下 ScaleGestureDetector 的基本使用。
ScaleGestureDetector 源码分析好了,现在我们进入本章重点,ScaleGestureDetector 源码分析,敲黑板敲黑板。首先,我们打开 ScaleGestureDetector 的源码可以看到,几乎所有的代码都集中在了 onTouchEvent 这个方法上,所以在这里,我就主要给大家介绍这个方法的实现。
第一部分:前期准备 if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } mCurrTime = event.getEventTime(); final int action = event.getActionMasked(); // Forward the event to check for double tap gesture if (mQuickScaleEnabled) { mGestureDetector.onTouchEvent(event); } final int count = event.getPointerCount(); final boolean isStylusButtonDown = (event.getButtonState() & MotionEvent.BUTTON_STYLUS_PRIMARY) != 0; mInputEventConsistencyVerifier输入事件一致性验证器 @有道
根据名字以及前面的定义
我们可以猜测这个对象应该是手势监听 Event 是否注册(连接到硬件)
所以,如果他为空,那么我们在这里调用 onTouchEvent 进行注册
if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } mCurrTime获得事件发生时的时间
mCurrTime = event.getEventTime(); action获得事件类型
final int action = event.getActionMasked(); mQuickScaleEnabledForward the event to check for double tap gesture
@有道 转发事件以检查双击手势
首先是 mQuickScaleEnabled 这个对象
翻译过来是: @有道 启用快速扩展
作用大概就是调用双击监听事件,比如双击最大化
if (mQuickScaleEnabled) { mGestureDetector.onTouchEvent(event); } count获得屏幕上手指的数目
final int count = event.getPointerCount(); isStylusButtonDown这个主要是由于判断手写笔是否按下
由于我们很少处理手写笔,所以这里不做过多说明
## 第二部分:处理与手势变化
用户的缩放手势不总是一定的,就是说对于用户而言,随时可能有手指碰触或离开屏幕,这就使得缩放中心的(焦点)随时可能发生变化,这部分主要是用来处理这一变化,并做出响应。
final boolean anchoredScaleCancelled = mAnchoredScaleMode == ANCHORED_SCALE_MODE_STYLUS && !isStylusButtonDown; final boolean streamComplete = action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || anchoredScaleCancelled; // 如果发生了上面这种小动作,或者说有一手指离开了屏幕,进行调用 if (action == MotionEvent.ACTION_DOWN || streamComplete) { // Reset any scale in progress with the listener. // If it's an ACTION_DOWN we're beginning a new event stream. // This means the app probably didn't give us all the events. Shame on it. if (mInProgress) { mListener.onScaleEnd(this); mInProgress = false; mInitialSpan = 0; mAnchoredScaleMode = ANCHORED_SCALE_MODE_NONE; } else if (inAnchoredScaleMode() && streamComplete) { mInProgress = false; mInitialSpan = 0; mAnchoredScaleMode = ANCHORED_SCALE_MODE_NONE; } if (streamComplete) { return true; } }### anchoredScaleCancelled
@Google 锚定规模取消