Android手势 怎么样才算长按(GestureDetector源码)

来源:互联网 发布:淘宝衣服兼职模特招聘 编辑:程序博客网 时间:2024/06/10 20:51

GestureDetector里onLongPress方法的回调来自

    private void dispatchLongPress() {        mHandler.removeMessages(TAP);        mDeferConfirmSingleTap = false;        mInLongPress = true;        mListener.onLongPress(mCurrentDownEvent); //这里    }
一看dispatch方法——HOHO 是的, 你没猜错 就是handler里分发的

GestureHandler(Handler handler) {            super(handler.getLooper());        }        @Override        public void handleMessage(Message msg) {            switch (msg.what) {            case SHOW_PRESS:                mListener.onShowPress(mCurrentDownEvent);                break;                            case LONG_PRESS:  //就是这个message控制了啦                dispatchLongPress();                break;                            case TAP:                // If the user's finger is still down, do not count it as a tap                if (mDoubleTapListener != null) {                    if (!mStillDown) {                        mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);                    } else {                        mDeferConfirmSingleTap = true;                    }                }                break;            default:                throw new RuntimeException("Unknown message " + msg); //never            }        }

Come on! 进入正题OnTouchEvent的手势处理

这个LONG_PRESS的message发送的地方有且只有一个

        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);  //喏喏 就是这里是一个delayMessage            }            mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);            handled |= mListener.onDown(ev);            break;
找到啦delay的时长总共是(TAP_TIMEOUT_LONGPRESS_TIMEOUT)

它们分别是多少呢?

    private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); //缺省500毫秒 Settings.Secure可设置    private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); //100毫秒

也就是说缺省总共0.6秒。

主题是解决了,那为什么要发一个延迟message哪?

因为如果不符合长按条件 咱可以取消啊

场景1: MOVE的时候

        case MotionEvent.ACTION_MOVE:            if (mInLongPress || mInContextClick) {                break;            }            final float scrollX = mLastFocusX - focusX;            final float scrollY = mLastFocusY - focusY;            if (mIsDoubleTapping) {                // Give the move events of the double-tap                handled |= mDoubleTapListener.onDoubleTapEvent(ev);            } else if (mAlwaysInTapRegion) { //这个前提条件看字面意思是所有区域都视为tap区域?                final int deltaX = (int) (focusX - mDownFocusX);                final int deltaY = (int) (focusY - mDownFocusY);                int distance = (deltaX * deltaX) + (deltaY * deltaY);                if (distance > mTouchSlopSquare) { //如果还没longPress就超出TouchSlop了                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);                    mLastFocusX = focusX;                    mLastFocusY = focusY;                    mAlwaysInTapRegion = false;                    mHandler.removeMessages(TAP);                    mHandler.removeMessages(SHOW_PRESS);                    mHandler.removeMessages(LONG_PRESS);//那你就没机会longPress了? 待验证前提条件                }                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;
场景2: UP的时候
        case MotionEvent.ACTION_UP:            mStillDown = false;            MotionEvent currentUpEvent = MotionEvent.obtain(ev);            if (mIsDoubleTapping) {                // Finally, give the up event of the double-tap                handled |= mDoubleTapListener.onDoubleTapEvent(ev);            } else if (mInLongPress) {                mHandler.removeMessages(TAP);                mInLongPress = false;            } else if (mAlwaysInTapRegion && !mIgnoreNextUpEvent) {                handled = mListener.onSingleTapUp(ev);                if (mDeferConfirmSingleTap && mDoubleTapListener != null) {                    mDoubleTapListener.onSingleTapConfirmed(ev);                }            } else if (!mIgnoreNextUpEvent) {                // 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;            mDeferConfirmSingleTap = false;            mIgnoreNextUpEvent = false;            mHandler.removeMessages(SHOW_PRESS);            mHandler.removeMessages(LONG_PRESS); //这是必然的            break;
场景3 按钮点击的时候?

    /**     * Analyzes the given generic motion event and if applicable triggers the     * appropriate callbacks on the {@link OnGestureListener} supplied.     *     * @param ev The current motion event.     * @return true if the {@link OnGestureListener} consumed the event,     *              else false.     */    public boolean onGenericMotionEvent(MotionEvent ev) {        if (mInputEventConsistencyVerifier != null) {            mInputEventConsistencyVerifier.onGenericMotionEvent(ev, 0);        }        final int actionButton = ev.getActionButton();        switch (ev.getActionMasked()) {            case MotionEvent.ACTION_BUTTON_PRESS:                if (mContextClickListener != null && !mInContextClick && !mInLongPress                        && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY                        || actionButton == MotionEvent.BUTTON_SECONDARY)) {                    if (mContextClickListener.onContextClick(ev)) {                        mInContextClick = true;                        mHandler.removeMessages(LONG_PRESS);                        mHandler.removeMessages(TAP);                        return true;                    }                }                break;            case MotionEvent.ACTION_BUTTON_RELEASE:                if (mInContextClick && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY                        || actionButton == MotionEvent.BUTTON_SECONDARY)) {                    mInContextClick = false;                    mIgnoreNextUpEvent = true;                }                break;        }        return false;    }

场景4 5 手势cancel和tap cancel的时候

    private void cancel() {        mHandler.removeMessages(SHOW_PRESS);        mHandler.removeMessages(LONG_PRESS);        mHandler.removeMessages(TAP);        mVelocityTracker.recycle();        mVelocityTracker = null;        mIsDoubleTapping = false;        mStillDown = false;        mAlwaysInTapRegion = false;        mAlwaysInBiggerTapRegion = false;        mDeferConfirmSingleTap = false;        mInLongPress = false;        mInContextClick = false;        mIgnoreNextUpEvent = false;    }    private void cancelTaps() {        mHandler.removeMessages(SHOW_PRESS);        mHandler.removeMessages(LONG_PRESS);        mHandler.removeMessages(TAP);        mIsDoubleTapping = false;        mAlwaysInTapRegion = false;        mAlwaysInBiggerTapRegion = false;        mDeferConfirmSingleTap = false;        mInLongPress = false;        mInContextClick = false;        mIgnoreNextUpEvent = false;    }