• ViewGroup和View事件传递部分代码分析记录


    点击事件产生后,发生了什么

    • 点击事件产生后,事件的传递时这样的顺序:Activity->Window->View;
    • 顶层View接收到事件后,会按照事件分发机制来分发事件;

    ViewGroup的事件传递过程

    • 事件传递给顶层View后,会调用VIewGroup的 dispatchTouchEvent方法;如果返回true,那么事件就会由ViewGroup处理;如果返回false,事件会传递给所在的点击事件链上的子View;子View的dispatchTouchEvent方法会被调用。
    • ViewGroup在调用dispatchTouchEvent方法后,会调用到注释1 处的onInterceptTouchEvent方法,返回true,表示会拦截事件,默认是返回false;
    • intercepted 方法返回true,注释2处 的代码块不会被执行;该代码块中,会遍历子View,最终调用到子View的dispatchEvent方法,详情如注释3;
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
        ......
                // Check for interception.
                final boolean intercepted;
                if (actionMasked == MotionEvent.ACTION_DOWN
                        || mFirstTouchTarget != null) {
                    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                    if (!disallowIntercept) {
                        intercepted = onInterceptTouchEvent(ev); // 注释1.
                        ev.setAction(action); // restore action in case it was changed
                    } else {
                        intercepted = false;
                    }
                } else {
                    // There are no touch targets and this action is not an initial down
                    // so this view group continues to intercept touches.
                    intercepted = true;
                }
    
    ......
                boolean alreadyDispatchedToNewTouchTarget = false;
                if (!canceled && !intercepted) {// 注释2
                ···
                                            newTouchTarget = getTouchTarget(child);
                                if (newTouchTarget != null) {
                                    // Child is already receiving touch within its bounds.
                                    // Give it the new pointer in addition to the ones it is handling.
                                    newTouchTarget.pointerIdBits |= idBitsToAssign;
                                    break;
                                }
    
                                resetCancelNextUpFlag(child);
                                // 注释3,调用子View的dispatchEvent方法
                                if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                    // Child wants to receive touch within its bounds.
                                    mLastTouchDownTime = ev.getDownTime();
                                    if (preorderedList != null) {
                                        // childIndex points into presorted list, find original index
                                        for (int j = 0; j < childrenCount; j++) {
                                            if (children[childIndex] == mChildren[j]) {
                                                mLastTouchDownIndex = j;
                                                break;
                                            }
                                        }
                                    } else {
                                        mLastTouchDownIndex = childIndex;
                                    }
                }
    ···
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    View对点击事件的处理

    • View和VIewGroup之前的差异,View的点击事件是自己处理,无法往下传递;
      ####分析
    • 1.判断时候设置了onTouchListener,如果onTouchListener的onTouch方法返回了true,那么注释1处的onTouchEvent方法就不会被调用;所以View的onTouchListener的优先级是高于onTouchEvent方法的;
    • 2.view的属性设置了clickable或者longClickable,那么就会消耗点击事件,如图注释2;
    • 3.在action_up事件发生时,会出发performClick方法,如果view设置了onclickListener,则会调用onClick方法,如图注释4;
        public boolean dispatchTouchEvent(MotionEvent event) {
                if (onFilterTouchEventForSecurity(event)) {
               if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
                   result = true;
               }
               //noinspection SimplifiableIfStatement
               ListenerInfo li = mListenerInfo;
               if (li != null && li.mOnTouchListener != null
                       && (mViewFlags & ENABLED_MASK) == ENABLED
                       && li.mOnTouchListener.onTouch(this, event)) {
                   result = true;
               }
       		// 注释1
               if (!result && onTouchEvent(event)) {
                   result = true;
               }
           }
    
           if (!result && mInputEventConsistencyVerifier != null) {
               mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
           }
           
    public boolean onTouchEvent(MotionEvent event) {
           final float x = event.getX();
           final float y = event.getY();
           final int viewFlags = mViewFlags;
           final int action = event.getAction();
    
       	// 注释2;
           final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
                   || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
                   || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
    
           if ((viewFlags & ENABLED_MASK) == DISABLED
                   && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) {
               if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
                   setPressed(false);
               }
               mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
               // A disabled view that is clickable still consumes the touch
               // events, it just doesn't respond to them.
               return clickable;
           }
           if (mTouchDelegate != null) {
               if (mTouchDelegate.onTouchEvent(event)) {
                   return true;
               }
           }
         if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
               switch (action) {
                   case MotionEvent.ACTION_UP:
              ......
                                   if (mPerformClick == null) {
                                   // 注释3
                                       mPerformClick = new PerformClick();
                                   }
                                   if (!post(mPerformClick)) {
                                       performClickInternal();
                                   }
                               }
                           }
    }
    
    
       public boolean performClick() {
           // We still need to call this method to handle the cases where performClick() was called
           // externally, instead of through performClickInternal()
           notifyAutofillManagerOnClick();
    
           final boolean result;
           final ListenerInfo li = mListenerInfo;
           if (li != null && li.mOnClickListener != null) {
           // 注释4
               playSoundEffect(SoundEffectConstants.CLICK);
               li.mOnClickListener.onClick(this);
               result = true;
           } else {
               result = false;
           }
    
           sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    
           notifyEnterOrExitForAutoFillIfNeeded(true);
    
           return result;
       } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    以上就是VIewGroup和View事件传递部分代码的简单分析;

  • 相关阅读:
    金蝶云星空企业版v8.0如何通过内网穿透实现异地公网远程访问
    五、2023.10.1.C++stl.5
    C++‘s most vexing parse
    为什么手机和电视ip地址不一样
    C++ set / multiset容器
    webpack编译报错Cannot find module ‘@babel/core‘且无法识别es6的reset语法
    数据挖掘与分析——特征选择
    【linux基础(六)】Linux中的开发工具(中)--gcc/g++
    webpack优化篇(四十二): 使用高版本的 webpack 和 Node.js
    中国户外休闲家具及用品市场发展规划趋势及运营状况研究报告2022年版
  • 原文地址:https://blog.csdn.net/TopWilling/article/details/126213569