总结Android事件分发过程
小计事件分发
原文地址
点击事件传递方向 activity->viewgroup(父类是View)->…->view.
1.activity 主要关心最后分发的结果,首先就向下分发,下面有消费者就结束,没有就调用activity的onTouchEvent(ev)
/ * 源码分析:Activity.dispatchTouchEvent() */ public boolean dispatchTouchEvent(MotionEvent ev) { // 仅贴出核心代码 if (getWindow().superDispatchTouchEvent(ev)) { return true; // 若getWindow().superDispatchTouchEvent(ev)的返回true // 则Activity.dispatchTouchEvent()就返回true,则方法结束。即 :该点击事件停止往下传递 & 事件传递过程结束 // 否则:继续往下调用Activity.onTouchEvent } return onTouchEvent(ev); }————————————————版权声明:本文为CSDN博主「Carson带你学Android」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/carson_ho/article/details/54136311
2.ViewGroup
Activity的getWindow().superDispatchTouchEvent(ev)向下分发给ViewGroup.DispatchTouchEvent(ev)
重点是:
viewgroup的前置onInterceptTouchEvent(ev)方法,决定了是否在这里先拦截,
若拦截,调用super.dispatchTouchEvent(ev); 即父类的view的dispatchTouchEvent(ev)方法,看3
不拦截 遍历子view的.dispatchTouchEvent(ev),向下分发
若都不消费,就也调用super.dispatchTouchEvent(ev);
/ * 源码分析:ViewGroup.dispatchTouchEvent() */ public boolean dispatchTouchEvent(MotionEvent ev) { // 仅贴出关键代码 ... if (disallowIntercept || !onInterceptTouchEvent(ev)) { // 分析2 // 1. 通过for循环,遍历当前ViewGroup下的所有子View for (int i = count - 1; i >= 0; i--) { if (child.dispatchTouchEvent(ev)) { //实现了点击事件从ViewGroup到子View的传递(具体请看下面章节介绍的View事件分发机制) //消费了就返回true return true; } } } ... return super.dispatchTouchEvent(ev); // 若无任何View接收事件(如点击空白处)/ViewGroup本身拦截了事件(复写了onInterceptTouchEvent()返回true) // 会调用ViewGroup父类的dispatchTouchEvent(),即View.dispatchTouchEvent() // 因此会执行ViewGroup的onTouch() -> onTouchEvent() -> performClick() -> onClick(),即自己处理该事件,事件不会往下传递 // 具体请参考View事件分发机制中的View.dispatchTouchEvent() ... }/ViewGroup.onInterceptTouchEvent() * a. 返回false:不拦截(默认) * b. 返回true:拦截,即事件停止往下传递(需手动复写onInterceptTouchEvent()其返回true) */ public boolean onInterceptTouchEvent(MotionEvent ev) { // 默认不拦截 return false; } ————————————————版权声明:本文为CSDN博主「Carson带你学Android」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/carson_ho/article/details/54136311
3. viewd的dispatchTouchEvent(ev)
重点在于 ontouch()和控件本来是否可以点击的属性,设置了 bool OnTouchListener(),并且根据返回值 ture 就消费了,整个事件结束,返回false,会接着判断是否能流向onclick(), 判断依据:控件本来是否可以点击的属性
/ * 源码分析:View.dispatchTouchEvent() */ public boolean dispatchTouchEvent(MotionEvent event) { if ( (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) {return true; } return onTouchEvent(event); } // 说明:只有以下3个条件都为真,dispatchTouchEvent()才返回true;否则执行onTouchEvent() // 1. (mViewFlags & ENABLED_MASK) == ENABLED // 2. mOnTouchListener != null // 3. mOnTouchListener.onTouch(this, event) // 下面对这3个条件逐个分析/ * 条件1:(mViewFlags & ENABLED_MASK) == ENABLED * 说明: * 1. 该条件是判断当前点击的控件是否enable * 2. 由于很多View默认enable,故该条件恒定为true(除非手动设置为false) *// * 条件2:mOnTouchListener != null * 说明: * 1. mOnTouchListener变量在View.setOnTouchListener()里赋值 * 2. 即只要给控件注册了Touch事件,mOnTouchListener就一定被赋值(即不为空) */ public void setOnTouchListener(OnTouchListener l) { mOnTouchListener = l; } / * 条件3:mOnTouchListener.onTouch(this, event) * 说明: * 1. 即回调控件注册Touch事件时的onTouch(); * 2. 需手动复写设置,具体如下(以按钮Button为例) */ button.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return false; // 若在onTouch()返回true,就会让上述三个条件全部成立,从而使得View.dispatchTouchEvent()直接返回true,事件分发结束 // 若在onTouch()返回false,就会使得上述三个条件不全部成立,从而使得View.dispatchTouchEvent()中跳出If,执行onTouchEvent(event) // onTouchEvent()源码分析 -> 分析1 } });/ * 分析1:onTouchEvent() */ public boolean onTouchEvent(MotionEvent event) { ... // 仅展示关键代码 // 若该控件可点击,则进入switch判断中 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { // 根据当前事件类型进行判断处理 switch (event.getAction()) { // a. 事件类型=抬起View(主要分析) case MotionEvent.ACTION_UP: performClick();// ->>分析2 break;// b. 事件类型=按下View case MotionEvent.ACTION_DOWN: break;// c. 事件类型=结束事件 case MotionEvent.ACTION_CANCEL: break; // d. 事件类型=滑动View case MotionEvent.ACTION_MOVE: } break; } // 若该控件可点击,就一定返回true return true; } // 若该控件不可点击,就一定返回false return false; }/ * 分析2:performClick() */ public boolean performClick() { if (mOnClickListener != null) { // 只要通过setOnClickListener()为控件View注册1个点击事件 // 那么就会给mOnClickListener变量赋值(即不为空) // 则会往下回调onClick() & performClick()返回true playSoundEffect(SoundEffectConstants.CLICK); mOnClickListener.onClick(this); return true; } return false; } ————————————————版权声明:本文为CSDN博主「Carson带你学Android」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/carson_ho/article/details/54136311