View.java

作者: 小虫虫奇遇记 | 来源:发表于2020-08-12 15:22 被阅读0次

1.事件分发
优先级:onTouch>onTouchEvent> OnLongClickListener>OnClickListener

  public boolean dispatchTouchEvent(MotionEvent event) {
            //先调用onTouch
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }
           // 再调用onTouchEvent
            if (!result && onTouchEvent(event)) {
                result = true;
            }
  }

public boolean onTouchEvent(MotionEvent event) {
switch(action){
 case MotionEvent.ACTION_UP:
  // Only perform take click actions if we were in the pressed state
   if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
 // of the view update before click actions start.
       if (mPerformClick == null) {
                      //处理点击事件
                         mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    //调用onClick方法
                                    performClickInternal();
                                }
                            }
   case MotionEvent.ACTION_DOWN:
            if (!clickable) {
                        //处理长按事件
                        checkForLongClick(0, x, y);
                        break;
                    }
case MotionEvent.ACTION_CANCEL:
                    if (clickable) {
                        setPressed(false);
                    }
                    removeTapCallback();
                    removeLongPressCallback();
                    mInContextButtonPress = false;
                    mHasPerformedLongPress = false;
                    mIgnoreNextUpEvent = false;
                    mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                    break;

                case MotionEvent.ACTION_MOVE:
                    if (clickable) {
                        drawableHotspotChanged(x, y);
                    }

                    // Be lenient about moving outside of buttons
                    if (!pointInView(x, y, mTouchSlop)) {
                        // Outside button
                        // Remove any future long press/tap checks
                        removeTapCallback();
                        removeLongPressCallback();
                        if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
                            setPressed(false);
                        }
                        mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                    }
                    break;
}
}

ACTION_CANCEL 触发时机:
子控件接收到down或move后,被父控件在 onInterceptTouchEvent 根据move位置进行拦截,将事件转换成cancel传给子控件 ,以至于子控件接受不到后续Up事件.

 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }

不过子View可以通过设置requestDisallowInterceptTouchEvent(true)来达到禁止父ViewGroup拦截事件的目的

  1. post方法为什么绘制后执行
public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }

/**
     * Returns the queue of runnable for this view.
     *
     * @return the queue of runnables for this view
     */
    private HandlerActionQueue getRunQueue() {
        if (mRunQueue == null) {
            mRunQueue = new HandlerActionQueue();
        }
        return mRunQueue;
    }
//dispatchAttachedToWindow中调用mRunQueue执行之前缓存的消息
 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
         ....
        // Transfer all pending runnables.
        if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
}

//dispatchAttachedToWindow调用时机
//ViewGroup.java  
// Android 26.0
public void addView(View child, int index, LayoutParams params) {
    ...
        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
        // therefore, we call requestLayout() on ourselves before, so that the child's request
        // will be blocked at our level
        requestLayout();
        invalidate(true);
        addViewInner(child, index, params, false);
    }

 private void addViewInner(View child, int index, LayoutParams params,
            boolean preventRequestLayout) {
    ....
 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
}

相关文章

网友评论

      本文标题:View.java

      本文链接:https://www.haomeiwen.com/subject/mmpsdktx.html