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. 关于ViewGroup和View的事件反向处理:
看看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,分别在Activity及View的 dispatchTouchEvent、onInterceptTouchEvent、
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