> 文档中心 > 总结Android事件分发过程

总结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

在这里插入图片描述

中评网简体版