自定义一个view,并实现最简单的手势识别功能(下)

源码分析:
首先熟悉一下GestureDetector文件接口。
frameworks/base/core/java/android/view/ GestureDetector.java
public class GestureDetector {
    public interface OnGestureListener {
        boolean onDown(MotionEvent e);
        void onShowPress(MotionEvent e);
        boolean onSingleTapUp(MotionEvent e);
        boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
        void onLongPress(MotionEvent e);
        boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
    }
    private final OnGestureListener mListener;

    public boolean onTouchEvent(MotionEvent ev) {
        switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_POINTER_DOWN:
             //当一个手指按下去后,触发的是ACTION_DOWN,只要手指不抬起来,当另一个手指按下去并且抬起来的时候,触发的是ACTION_POINTER_DOWN。
            break;
        case MotionEvent.ACTION_POINTER_UP:
              //当一个手指抬起后,屏幕上还有另一个手指按下去的时候,触发的是ACTION_POINTER_DOWN。
            break;
        case MotionEvent.ACTION_DOWN:
            if (mIsLongpressEnabled) {
                mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
                        + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
            }
            mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
              //当一个手指按下去后,触发的是ACTION_DOWN,回调函数onDown()。
            handled |= mListener.onDown(ev);
            break;
        case MotionEvent.ACTION_MOVE:
            final float scrollX = mLastFocusX - focusX;
            final float scrollY = mLastFocusY - focusY;
            if (mIsDoubleTapping) {
                // Give the move events of the double-tap  如果是双击事件触发onDoubleTapEvent
                handled |= mDoubleTapListener.onDoubleTapEvent(ev);
            } else if (mAlwaysInTapRegion) {
                //如果是在点击同一个位置,并且符合滑动的距离,触发onscroll事件
                final int deltaX = (int) (focusX - mDownFocusX);
                final int deltaY = (int) (focusY - mDownFocusY);
                int distance = (deltaX * deltaX) + (deltaY * deltaY);
                if (distance > mTouchSlopSquare) {
                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                    mLastFocusX = focusX;
                    mLastFocusY = focusY;
                    mAlwaysInTapRegion = false;
                    mHandler.removeMessages(TAP);
                    mHandler.removeMessages(SHOW_PRESS);
                    mHandler.removeMessages(LONG_PRESS);
                }
                if (distance > mDoubleTapTouchSlopSquare) {
                    mAlwaysInBiggerTapRegion = false;
                }
            } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
                handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                mLastFocusX = focusX;
                mLastFocusY = focusY;
            }
            break;
        case MotionEvent.ACTION_UP:
            mStillDown = false;
            MotionEvent currentUpEvent = MotionEvent.obtain(ev);
            if (mIsDoubleTapping) {
                // Finally, give the up event of the double-tap  如果是双击触发onDoubleTapEvent事件
                handled |= mDoubleTapListener.onDoubleTapEvent(ev);
            } else if (mInLongPress) {
                mHandler.removeMessages(TAP);
                mInLongPress = false;
            } else if (mAlwaysInTapRegion) {
                handled = mListener.onSingleTapUp(ev);
            } else {
                //判断是不是要触发onFling方法
                // A fling must travel the minimum tap distance
                final VelocityTracker velocityTracker = mVelocityTracker;
                final int pointerId = ev.getPointerId(0);
                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
                final float velocityY = velocityTracker.getYVelocity(pointerId);
                final float velocityX = velocityTracker.getXVelocity(pointerId);
                if ((Math.abs(velocityY) > mMinimumFlingVelocity)
                        || (Math.abs(velocityX) > mMinimumFlingVelocity)){
                    handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
                }
            }
            if (mPreviousUpEvent != null) {
                mPreviousUpEvent.recycle();
            }
            // Hold the event we obtained above - listeners may have changed the original.
            mPreviousUpEvent = currentUpEvent;
            if (mVelocityTracker != null) {
                // This may have been cleared when we called out to the
                // application above.
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
            mIsDoubleTapping = false;
            mHandler.removeMessages(SHOW_PRESS);
            mHandler.removeMessages(LONG_PRESS);
            break;
        }
        return handled;
    }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case SHOW_PRESS:
                mListener.onShowPress(mCurrentDownEvent);
                break;
            case LONG_PRESS:
                dispatchLongPress();
                break;
        }
    private void dispatchLongPress() {
        mHandler.removeMessages(TAP);
        mInLongPress = true;
        mListener.onLongPress(mCurrentDownEvent);
    }
}

通过分析类GestureDetector,获悉内部接口OnGestureListener成员函数onDown;onShowPress;onSingleTapUp;onScroll;onLongPress;onFling;当类GestureDetector中的函数onTouchEvent被调用时,通过接口 mListener分别对内部接口OnGestureListener成员函数onDown;onShowPress;onSingleTapUp;onScroll;onLongPress;onFling进行调用。
针对以上log信息分析如下:
最后输出log如下:
1,点击屏幕后log输出如下
04-11 13:48:18.572: V/MYVIEW(5846): onTouch()-------------------pass
04-11 13:48:18.572: V/MYVIEW(5846): onDown()-------------------pass
04-11 13:48:18.616: V/MYVIEW(5846): onTouch()-------------------pass
04-11 13:48:18.616: V/MYVIEW(5846): onSingleTapUp()-------------------pass
步骤一,点击触摸屏,触摸屏被按下,即动作为 MotionEvent.ACTION_DOWN,进入mListener.onDown(ev)并回调操作;
步骤二,触摸屏按下操作被释放,即动作为 MotionEvent.ACTION_UP,由于没有对触摸屏做双击和长按操作,所以 mIsDoubleTapping, mInLongPress为false,点击触摸屏是同一个位置,所以 mAlwaysInTapRegion为true,进入mListener.onSingleTapUp(ev)并回调操作。

2,小幅度滑动屏幕后log输出如下
04-11 13:50:22.711: V/MYVIEW(6129): onDown()-------------------pass
04-11 13:50:22.736: V/MYVIEW(6129): onTouch()-------------------pass
04-11 13:50:22.736: V/MYVIEW(6129): onScroll()-------------------pass
04-11 13:50:22.746: V/MYVIEW(6129): onTouch()-------------------pass
04-11 13:50:22.746: V/MYVIEW(6129): onScroll()-------------------pass
04-11 13:50:22.766: V/MYVIEW(6129): onTouch()-------------------pass
04-11 13:50:22.766: V/MYVIEW(6129): onScroll()-------------------pass
步骤一,点击触摸屏,触摸屏被按下,即动作为 MotionEvent.ACTION_DOWN,进入mListener.onDown(ev)并回调操作;
步骤二,滑动触摸屏操作,即动作为 MotionEvent.ACTION_MOVE,当滑动的距离符合以下两个条件 distance > mTouchSlopSquare或(Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)则进入 mListener.onScroll并回调操作

3,大幅度滑动屏幕后log输出如下
04-11 13:50:22.711: V/MYVIEW(6129): onTouch()-------------------pass
04-11 13:50:22.711: V/MYVIEW(6129): onDown()-------------------pass
04-11 13:50:22.736: V/MYVIEW(6129): onTouch()-------------------pass
04-11 13:50:22.736: V/MYVIEW(6129): onScroll()-------------------pass
04-11 13:50:22.746: V/MYVIEW(6129): onTouch()-------------------pass
04-11 13:50:22.746: V/MYVIEW(6129): onScroll()-------------------pass
04-11 13:50:22.766: V/MYVIEW(6129): onTouch()-------------------pass
04-11 13:50:22.766: V/MYVIEW(6129): onScroll()-------------------pass
04-11 13:50:22.777: V/MYVIEW(6129): onTouch()-------------------pass
04-11 13:50:22.777: V/MYVIEW(6129): onFling()-------------------pass
步骤一,点击触摸屏,触摸屏被按下,即动作为 MotionEvent.ACTION_DOWN,进入mListener.onDown(ev)并回调操作;
步骤二,滑动触摸屏操作,即动作为 MotionEvent.ACTION_MOVE,当滑动的距离符合以下两个条件 distance > mTouchSlopSquare或(Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)则进入 mListener.onScroll并回调操作;
步骤三,当 满足条件Math.abs(velocityY) > mMinimumFlingVelocity时,则进入 mListener.onFling并回调操作。

4,长按屏幕后log输出如下
04-11 14:05:01.006: V/MYVIEW(6349): onTouch()-------------------pass
04-11 14:05:01.006: V/MYVIEW(6349): onDown()-------------------pass
04-11 14:05:01.127: V/MYVIEW(6349): onShowPress()-------------------pass
04-11 14:05:01.626: V/MYVIEW(6349): onLongPress()-------------------pass
04-11 14:05:04.690: V/MYVIEW(6349): onTouch()-------------------pass
步骤一,点击触摸屏,触摸屏被按下,即动作为 MotionEvent.ACTION_DOWN,进入mListener.onDown(ev)并回调操作;
步骤二,触摸屏一直被按下,并在mCurrentDownEvent.getDownTime() + TAP_TIMEOUT 时间段内没有动作 MotionEvent.ACTION_MOVE,故mHandler成功发送消息SHOW_PRESS,由  handleMessage处理,进入 mListener.onShowPress并回调操作,
步骤三,在触摸屏被按下后 mCurrentDownEvent.getDownTime()+TAP_TIMEOUT+ LONGPRESS_TIMEOUT后的时间内,触摸屏一直保持该状态,则mHandler成功发送消息LONG_PRESS,由  handleMessage处理,进入 mListener.onLongPress 并回调操作。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值