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