android的事件分发机制

android的事件分发机制 参考文章图解 Android 事件分发机制这个文章很早我就看过了但是只是知道是这个流程具体怎么操作点击事件如何传递依然有点迷甚至连这个流程图是否正确都不敢持肯定态度所以今天就来用代码实现下毕竟眼见为实嘛。debug过程太繁琐这里就不一步步贴了直接上带注释的结果1、点击viewgroup时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onTouchEvent { super } 》viewgroup.setOnClickListener2、点击view时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onInterceptTouchEvent { super } 》 view.dispatchTouchEvent { super } 》view.onTouchEvent { super } 》view.setOnClickListener3、activity的dispatchTouchEvent返回true或者false时事件分发流程activity.dispatchTouchEvent { true/false } 》无4、viewgroup的dispatchTouchEvent返回true时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { true } 》无5、viewgroup的dispatchTouchEvent返回false时事件分发流程activity.dispatchTouchEvent { super } 》activity.onTouchEvent { super } 》无6、viewgroup的onInterceptTouchEvent返回true时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onInterceptTouchEvent { true } 》 viewgroup.onTouchEvent { super } 》viewgroup.setOnClickListener7、viewgroup的onInterceptTouchEvent返回false时事件分发流程和super一样activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onInterceptTouchEvent { false } 》 view.dispatchTouchEvent { super } 》view.onTouchEvent { super } 》view.setOnClickListener8、view的dispatchTouchEvent返回true时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onInterceptTouchEvent { super } 》 view.dispatchTouchEvent { true } 》无9、view的dispatchTouchEvent返回false时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onTouchEvent { super } 》viewgroup.setOnClickListener10、view的onTouchEvent返回true时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onInterceptTouchEvent { super } 》 view.dispatchTouchEvent { super } 》view.onTouchEvent { true } 》无11、view的onTouchEvent返回false时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onTouchEvent { super } 》viewgroup.setOnClickListener12、viewgroup的onTouchEvent返回true时事件分发流程activity.dispatchTouchEvent { super } 》viewgroup.dispatchTouchEvent { super } 》viewgroup.onTouchEvent { true } 》无13、viewgroup的onTouchEvent返回false时事件分发流程activity.dispatchTouchEvent { super } 》activity.onTouchEvent { super } 》无14、activity的onTouchEvent返回true或者false时事件分发流程activity.onTouchEvent { true/false } 》无super.dispatchTouchEvent也是返回true、false为什么和直接设置 dispatchTouchEvent{ true、false }效果完全不一样呢这个消费是什么意思dispatchTouchEvent 返回 true 只代表这次 MotionEvent 被消费了但它不等于点击事件onClick一定发生。这两件事在源码里是分开的。true事件被消费不再向父级回传本次调用直接结束false事件没被消费上交父 ViewGroup 的 onTouchEventsuper.dispatchTouchEvent()走默认分发逻辑拦截判断 → 遍历子 View → 自身 onTouchEventsuper.dispatchTouchEvent()返回 true 是因为内部的 onTouchEvent 返回了 true或者子 View 消费了。整个事件序列走完了完整的 U 型链路viewgroup的onInterceptTouchEvent是不是有点多余当 ViewGroup 通过onInterceptTouchEvent返回 true 拦截事件时原先正在处理事件的子 View 会收到一个ACTION_CANCEL告诉它事件序列被抢走了请你重置状态。如果你直接在dispatchTouchEvent里 return true系统不会自动给子 View 补发 CANCEL。子 View 会永远卡在按下状态——按钮高亮清不掉、RecyclerView 的滚动状态无法复位。dispatchTouchEvent方法有有一整套分发遍历流程如果直接设置就需要手动配置这些逻辑所以onInterceptTouchEvent才会被抽出单独来管是否拦截具体到代码上如何设置拦截外部拦截法父主导父在onInterceptTouchEvent的 MOVE 中根据滑动方向决定拦截内部拦截法子主导子在dispatchTouchEvent里根据业务逻辑调用requestDisallowInterceptTouchEvent调用后父 ViewGroup 的onInterceptTouchEvent在后续 MOVE/UP 中会被跳过/** * 事件分发测试 * activity层 */ public class MainActivity extends AppCompatActivity { private LinearlayoutViewGroup mViewGroup; private TextViewView mView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mViewGroup findViewById(R.id.mViewGroup); mView findViewById(R.id.mView); mViewGroup.setOnClickListener(v - { Log.e(点击, ViewGroup点击事件触发); }); mView.setOnClickListener(v - { Log.e(点击, View点击事件触发); }); } /** * event 普通点击会触发三次ACTION_DOWN、ACTION_MOVE、ACTION_UP * 这里只讨论 ACTION_UP 的传递流程 * return super 默认方法 点击viewgroup和view时传递到viewgroup 的 dispatchTouchEvent 方法 * return true/false 事件到这里结束 */ Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() 1) Log.e(点击, activity-dispatchTouchEvent); return super.dispatchTouchEvent(event); } /** * return super/true/false activity的点击事件触发事件到这里结束 */ Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() 1) Log.e(点击, activity-onTouchEvent); return super.onTouchEvent(event); } }/** * viewGroup层 */ public class LinearlayoutViewGroup extends LinearLayout { public LinearlayoutViewGroup(Context context) { super(context); } public LinearlayoutViewGroup(Context context, Nullable AttributeSet attrs) { super(context, attrs); } public LinearlayoutViewGroup(Context context, Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public LinearlayoutViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } /** * return super 默认方法点击viewgroup时传递给自己的 onTouchEvent 方法。点击view时传递给自己的 dispatchTouchEvent 方法 * return true 事件到这里结束 * return false 事件传递给acivity的 onTouchEvent 方法 */ Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() 1) Log.e(点击, ViewGroup-dispatchTouchEvent); return super.dispatchTouchEvent(event); } /** * 判断是否拦截了某个事件 * return super/false 默认方法点击view时传递到view的 dispatchTouchEvent 方法 * return true 事件传递给自己的 onTouchEvent 方法 */ Override public boolean onInterceptTouchEvent(MotionEvent event) { if (event.getAction() 1) Log.e(点击, ViewGroup-onInterceptTouchEvent); return super.onInterceptTouchEvent(event); } /** * return super 默认方法点击viewgroup时触发viewgroup的 setOnClickListener 方法 * return true 事件到这里结束 * return false 事件传递到activity的 onTouchEvent 方法 */ Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() 1) Log.e(点击, ViewGroup-onTouchEvent); return super.onTouchEvent(event); } }/** * view层 */ //SuppressLint(AppCompatCustomView) public class TextViewView extends View { public TextViewView(Context context) { super(context); } public TextViewView(Context context, Nullable AttributeSet attrs) { super(context, attrs); } public TextViewView(Context context, Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public TextViewView(Context context, Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } /** * return super 默认方法点击view时传递给自己的 onTouchEvent 方法。 * return true 事件到这里结束 * return false 事件传递给viewgroup的 onTouchEvent 方法 */ Override public boolean dispatchTouchEvent(MotionEvent event) { if (event.getAction() 1) Log.e(点击, View-dispatchTouchEvent); return super.dispatchTouchEvent(event); } /** * return super 默认方法点击view时触发view的 setOnClickListener 方法 * return true 事件到这里结束 * return false 事件传递给viewgroup的 onTouchEvent 方法 */ Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() 1) Log.e(点击, View-onTouchEvent); return super.onTouchEvent(event); } }