记View onTouch onClick onLongClick如何触发

view的dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent event) {
     ...
     
     if (onFilterTouchEventForSecurity(event)) {
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                result = true;
            }
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;

           // 判断有没有设置onTouchListener 并且view是否是enable 
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

             // onTouch返回false 调用onTouchEvent处理
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }
        ...
                return result;

        }

在View的dispatchEvent里面会判断用户如果设置了onTouchListener,并且view enable属性为true,就会调用onTouch方法,如果onTouch返回true ,则不会再去调用onTouchEvent();

问题: 当对view设置了setOnTouchListener监听之后,onTouch方法会被调用几次?

在view的daipatchTouchEvent()中,当有事件来临时如果onTouchEventListener不为空,并且view enable为true时,就会调用onTouch() 所以当点击某个按钮又抬起时 会调用两次onTouch, down事件一次,up事件一次,如果有滑动屏幕时,会调用多次,因为会一直产生move事件

view的onTouchEvent

public boolean onTouchEvent(MotionEvent event) {
    ...
           //主要看这一段
            if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
            switch (action) {
             
                case MotionEvent.ACTION_UP:
                   ... 
                    if (!clickable) {
                        removeTapCallback();
                        removeLongPressCallback();
                        mInContextButtonPress = false;
                        mHasPerformedLongPress = false;
                        mIgnoreNextUpEvent = false;
                        break;
                    }
                      .....
                        // mHasPerformedLongPress 当onLongClick()返回true时,将该属性置为true
                        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                           // 将长按计时取消
                            removeLongPressCallback();

                            if (!focusTaken) {
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                              // 处理onClick()
                                if (!post(mPerformClick)) {
                                    performClickInternal();
                                }
                            }
                        }

                   ......
                    break;

                case MotionEvent.ACTION_DOWN:
                    if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {
                        mPrivateFlags3 |= PFLAG3_FINGER_DOWN;
                    }
                    mHasPerformedLongPress = false;

                   // 开始长按计时
                    if (!clickable) {
                        checkForLongClick(
                               ViewConfiguration.getLongPressTimeout(),
                                x,
                                y,
                                TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS);
                        break;
                    }
             .....
            return true;
        }
}

在onTouchEvent()中,当down事件来时,会开始长按计时

  private void checkForLongClick(long delay, float x, float y, int classification) {
        if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) {
            mHasPerformedLongPress = false;

         //创建一个计时任务
            if (mPendingCheckForLongPress == null) {
                mPendingCheckForLongPress = new CheckForLongPress();
            }
            mPendingCheckForLongPress.setAnchor(x, y);
            mPendingCheckForLongPress.rememberWindowAttachCount();
            mPendingCheckForLongPress.rememberPressedState();
            mPendingCheckForLongPress.setClassification(classification);
            
            //将任务post进Handler
            postDelayed(mPendingCheckForLongPress, delay);
        }
    }

//计时任务run()
    @Override
        public void run() {
            if ((mOriginalPressedState == isPressed()) && (mParent != null)
                    && mOriginalWindowAttachCount == mWindowAttachCount) {
                recordGestureClassification(mClassification);
                //调用onLongClick() 返回true时 将mHasPerformedLongPress置为true
                if (performLongClick(mX, mY)) {
                    mHasPerformedLongPress = true;
                }
            }
        }

所以onLongClick是在手指触摸屏幕之时开始计时,当到达时间后触发onLongClick() ,onLongClick()返回true后将mHasPerformedLongPress改为true

在Up事件处理时会去判断 如果onLongClick如果没有被触发或者onLongClick返回false,将长按计时取消 然后去触发onClick