android4.4之GestureDetector(手势识别)
应用如果需要复杂的手势匹配,这时候可以使用GestureDetector来实现。
实现步骤:
1、实现OnGestureListener类,也可继承SimpleOnGestureListener类然后复写相应函数;
2、创建一个GestureDetector类对象,然后new一个第1步中自定义的监听类对象作为参数穿进去;
3、在接收到MotionEvent事件时,调用OnGestureListener.onTouchEvent(onTouchEvent)函数。
对手势匹配做的一些自定义处理在手势监听类中实现。
下面对以上三步做一些简单分析:先看GestureDetector构造函数
public GestureDetector(Context context, OnGestureListener listener, Handler handler) { if (handler != null) { mHandler = new GestureHandler(handler); } else { mHandler = new GestureHandler(); } mListener = listener; if (listener instanceof OnDoubleTapListener) { setOnDoubleTapListener((OnDoubleTapListener) listener); } init(context); }从构造函数看出new一个GestureDetector对象需要一个OnGestureListener对象,该对象保存在mListener中,如果手势监听是继承SimpleOnGestureListener类,那么还会调用setOnDoubleTapListener()。init函数做一些初始化函数,先不看。
接着看第3步OnGestureListener.onTouchEvent(onTouchEvent)函数处理。此函数稍微有点长,分段阅读
public boolean onTouchEvent(MotionEvent ev) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(ev, 0); } final int action = ev.getAction(); if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); final boolean pointerUp = (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP; final int skipIndex = pointerUp ? ev.getActionIndex() : -1; // Determine focal point float sumX = 0, sumY = 0; final int count = ev.getPointerCount(); for (int i = 0; i < count; i++) { if (skipIndex == i) continue; sumX += ev.getX(i); sumY += ev.getY(i); } final int div = pointerUp ? count - 1 : count; final float focusX = sumX / div; final float focusY = sumY / div; boolean handled = false;InputEventConsistencyVerifier是调试用的,mVelocityTracker是一个速度追踪类对象,紧接着的这段代码逻辑是求一个MotionEvent的中心点,这边调试时发现getPointerCount只有一个点而已,不管是点击或滑动。接着往下看
switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_POINTER_DOWN: mDownFocusX = mLastFocusX = focusX; mDownFocusY = mLastFocusY = focusY; // Cancel long press and taps cancelTaps(); break; case MotionEvent.ACTION_POINTER_UP: mDownFocusX = mLastFocusX = focusX; mDownFocusY = mLastFocusY = focusY; // Check the dot product of current velocities. // If the pointer that left was opposing another velocity vector, clear. mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); final int upIndex = ev.getActionIndex(); final int id1 = ev.getPointerId(upIndex); final float x1 = mVelocityTracker.getXVelocity(id1); final float y1 = mVelocityTracker.getYVelocity(id1); for (int i = 0; i < count; i++) { if (i == upIndex) continue; final int id2 = ev.getPointerId(i); final float x = x1 * mVelocityTracker.getXVelocity(id2); final float y = y1 * mVelocityTracker.getYVelocity(id2); final float dot = x + y; if (dot < 0) { mVelocityTracker.clear(); break; } } break; case MotionEvent.ACTION_DOWN: if (mDoubleTapListener != null) { boolean hadTapMessage = mHandler.hasMessages(TAP); if (hadTapMessage) mHandler.removeMessages(TAP); if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage && isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) { // This is a second tap mIsDoubleTapping = true; // Give a callback with the first tap of the double-tap handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); // Give a callback with down event of the double-tap handled |= mDoubleTapListener.onDoubleTapEvent(ev); } else { // This is a first tap mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); } } mDownFocusX = mLastFocusX = focusX; mDownFocusY = mLastFocusY = focusY; if (mCurrentDownEvent != null) { mCurrentDownEvent.recycle(); } mCurrentDownEvent = MotionEvent.obtain(ev); mAlwaysInTapRegion = true; mAlwaysInBiggerTapRegion = true; mStillDown = true; mInLongPress = false; mDeferConfirmSingleTap = false; if (mIsLongpressEnabled) { mHandler.removeMessages(LONG_PRESS); mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT + LONGPRESS_TIMEOUT); } mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); handled |= mListener.onDown(ev); break;
对于ACTION_DOWN事件,调用mListener.onDown(ev);处理,mListener是指向第1步中定义的手势监听类对象。对于MotionEvent.ACTION_MOVE事件,调用mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);函数,mCurrentDownEvent是当前滑动手势中的按下点,ev是当前触摸点,scrollX、scrollY是当前触摸点跟上一个触摸点的x/y轴偏移量。对于ACTION_UP事件,调用mListener.onSingleTapUp(ev)或者mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);函数。
未完待续。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。