View事件分发流程

App应用界面结构:





1.      关于Activity的事件分发开始dispatchTouchEvent:

dispatchTouchEvent:

   Activity - > PhoneWindow -> DecorView(继承FrameLayout(ViewGroup))

DecorView.superDispatchTouchEvent() 调用父类super.dispatchTouchEvent(),即ViewGroup。

 那么,如果逐级call后返回false时,将调用Activity的onTouchEvent消费事件。


2.     关于View的事件分发机制从dispatchTouchEvent开始

当事件在View中分发时,简单逻辑如下:
  boolean dispatchTouchEvent(){
       boolean result =  fasle;
       result = mOnTouchListener.onTouch(this, event);  // 表示设置TouchListener情形
       if(!result && onTouchEvent(event)){
            result = true
        }
         return result;
   }
  boolean onTouchEvent(MotionEvent event) ; 进行事件的消费处理 return false /true,将会传给ViewGroup

3.  关于ViewGroupView的事件反向处理:

 看看ViewGroup下发时的逻辑及View未消费的反向到ViewGroup的onTouchEvent()逻辑。

2481    public boolean dispatchTouchEvent(MotionEvent ev) {
2492        boolean handled = false;
2493        if (onFilterTouchEventForSecurity(ev)) {
2507            final boolean intercepted;
2508            if (actionMasked == MotionEvent.ACTION_DOWN
2509                    || mFirstTouchTarget != null) {
2510                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
2511                if (!disallowIntercept) {
2512                    intercepted = onInterceptTouchEvent(ev);  // 事件拦截处理函数
2513                    ev.setAction(action); // restore action in case it was changed
2514                } else {
2515                    intercepted = false;
2516                }
2517            } else {
2520                intercepted = true;
2521            }
2537            if (!canceled && !intercepted) {
2568                        for (int i = childrenCount - 1; i >= 0; i--) {
2601                            if (dispatchTransformedTouchEvent(ev, false, child,idBitsToAssign)) {
2617                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
2618                                alreadyDispatchedToNewTouchTarget = true;
2619                                break;    // 遍历找接收event的子View并向下发事件,
                                 }
                             }
                 }
2641            // Dispatch to touch targets.
2642            if (mFirstTouchTarget == null) {  // 将事件分发给自己dispatchTouchEvent, 本View处理
2643                // No touch targets so treat this as an ordinary view. 
2644              handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);
2646            } else {
2649                TouchTarget predecessor = null;
2650                TouchTarget target = mFirstTouchTarget;
2652                while (target != null && mFirstTouchTarget != null) {
2654                    final TouchTarget next = target.next;
2655                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
2656                        handled = true;
2658                    }else{
668                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
2669                                || intercepted;
2670                        if (dispatchTransformedTouchEvent(ev, cancelChild,
2671                                target.child, target.pointerIdBits)) {
2672                            handled = true;
2673                        }
                        }
                }
            }
2705        return handled;
2706    }

案例:layout布局ParentView 包裹一个 ChildView,分别在ActivityView dispatchTouchEventonInterceptTouchEvent

onTouchEvent添加log和堆栈打印。点击 ChildView,查看事件分发流程

  自定义 ParentView extends LinearLayout

  自定义 ChildView extends View


 07:13:59.250 /com D/MainActivity:  super dispatchTouchEvent = event =MotionEvent { action=ACTION_DOWN
 07:13:59.264 /com D/ParentView:  super dispatchTouchEvent = event =MotionEvent { action=ACTION_DOWN
 07:13:59.267 /com D/ParentView:  super onInterceptTouchEvent = event =MotionEvent { action=ACTION_DOWN
 07:13:59.323 /com D/ChildView:  super dispatchTouchEvent = event =
    java.lang.Exception
        at com.myapplication.ChildView.dispatchTouchEvent(ChildView.java:23)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2981)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2601)
        at com.myapplication.ParentView.dispatchTouchEvent(ParentView.java:29)
		
 07:13:59.325 /com D/ChildView:  super onTouchEvent = event =MotionEvent { action=ACTION_DOWN
 07:13:59.367 /com D/ParentView:  super onTouchEvent = event =
    java.lang.Exception
        at com.myapplication.ParentView.onTouchEvent(ParentView.java:34)
        at android.view.View.dispatchTouchEvent(View.java:11810)                       
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2975)    
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2644)              
        at com.myapplication.ParentView.dispatchTouchEvent(ParentView.java:29)      
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2981)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2601)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2981)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2601)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2981)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2601)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2981)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2601)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2981)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2601)           
        at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:475)
        at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1829)
        at android.app.Activity.dispatchTouchEvent(Activity.java:3322)
        at com.myapplication.MainActivity.dispatchTouchEvent(MainActivity.java:23)

 07:13:59.369 /com D/MainActivity:  super onTouchEvent = event =MotionEvent { action=ACTION_DOWN
 07:13:59.377 /com D/MainActivity:  super dispatchTouchEvent = event =MotionEvent { action=ACTION_UP
 07:13:59.381 /com D/MainActivity:  super onTouchEvent = event =MotionEvent { action=ACTION_UP




·        super:调用父类方法

·        true:消费事件,即事件不继续往下传递

·        false:不消费事件,事件也不继续往下传递 / 交由给父控件onTouchEvent()处理

分发机制:由父控件判断是否拦截,如果不拦截事件,则继续分发到子控件,然后一直分发下去。

处理:与分发相反,由子控件先处理事件,如果子控件不处理,则交给父控件处理,一直向上传递,直到那个控件处理了触摸事件




参考:https://blog.csdn.net/carson_ho/article/details/54136311


猜你喜欢

转载自blog.csdn.net/snail201211/article/details/79771789
今日推荐