android事件分发touchevent的dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent理解

参考:https://blog.csdn.net/morgan_xww/article/details/9372285

https://www.jianshu.com/p/35a8309b9597

基础知识

布局可定义应用中的界面结构(例如 Activity 的界面结构)。布局中的所有元素均使用 View 和 ViewGroup 对象的层次结构进行构建。View 通常绘制用户可查看并进行交互的内容。然而,ViewGroup 是不可见容器,用于定义 View 和其他 ViewGroup 对象的布局结构,如图 1 所示。

View 对象通常称为“微件”,可以是众多子类之一,例如 Button 或 TextView。
ViewGroup 对象通常称为“布局”,可以是提供其他布局结构的众多类型之一,例如 LinearLayout 或 ConstraintLayout。

touch事件3个方法:
public boolean dispatchTouchEvent(MotionEvent ev);    //用来分派event;从ViewGroup往view派发
public boolean onInterceptTouchEvent(MotionEvent ev); //用来拦截event;返回true表示拦截
public boolean onTouchEvent(MotionEvent ev);          //用来处理event;处理触控

Activity类  Activity dispatchTouchEvent();             onTouchEvent();
ViewGroup子类 FrameLayout、LinearLayout、ListView等   dispatchTouchEvent();   onInterceptTouchEvent();
onTouchEvent();
View控件 Button、TextView、EditText…… dispatchTouchEvent();
onTouchEvent();
dispatchTouchEvent() 用来分派事件。
其中调用了onInterceptTouchEvent()和onTouchEvent(),一般不重写该方法
onInterceptTouchEvent() 用来拦截事件。
ViewGroup类中的源码实现就是{return false;}表示不拦截该事件,
事件将向下传递(传递给其子View);
若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递,
事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法
 
onTouchEvent() 用来处理事件。
返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View);
返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理

此处参考:https://blog.csdn.net/morgan_xww/article/details/9372285

重点掌握

touch消息种类(基础版)

ACTION_DOWN->按下

ACTION_MOVE->移动

ACTION_UP->松开

dispatchTouchEvent-事件分发顺序

dispatchTouchEvent比较复杂,可以按照下面这张图分析:ViewGroup和View组成了一棵树形结构,最顶层为Activity的ViewGroup,下面有若干的ViewGroup节点,每个节点之下又有若干的ViewGroup节点或者View节点,依次类推。

  当一个Touch事件(ACTION_DOWN)依次下发,下发的过程是调用子View(ViewGroup)的dispatchTouchEvent方法实现的。简单来说,就是ViewGroup遍历它包含着的子View,调用每个View的dispatchTouchEvent方法,而当子View为ViewGroup时,又会通过调用ViewGroup的dispatchTouchEvent方法继续调用其内部的View的dispatchTouchEvent方法。上述例子中的消息action_down下发顺序是这样的:①-②-⑤-⑥-⑦-③-④。
  dispatchTouchEvent方法只负责事件的分发,它拥有boolean类型的返回值,当返回为true时,(ACTION_MOVE与ACTION_UP)顺序下发会中断。在上述例子中如果⑤的dispatchTouchEvent返回结果为true,那么⑥-⑦-③-④将都接收不到本次Touch事件但只收到了(ACTION_DOWN)。
  ViewGroup的dispatchTouchEvent是真正在执行“分发”工作,而View的dispatchTouchEvent方法,并不执行分发工作,或者说它分发的对象就是自己,决定是否把touch事件交给自己处理,而处理的方法,便是onTouchEvent事件。

onTouchEvent-事件处理

  • 如果返回值是true,表示消费(consume)了这个事件。以ACTION_DOWN为例,如果某个控件的onTouchEvent返回值为true,则后续的n个ACTION_MOVE与1个ACTION_UP都会逐层(通过ViewGroup,不会再遍历View)传递到这个控件的onTouchEvent进行处理。
  • 如果返回值是false,则会将ACTION_DOWN传递给其父ViewGroup的onTouchEvent进行处理,直到由哪一层ViewGroup消费了ACTION_DOWN事件为止。
  •  
  • 由于触摸事件都是连续的。如果ACTION_MOVE传递到子控件,而子控件的onTouchEvent返回值是false,即没有处理该ACTION_MOVE事件,则后续的ACTION_UP就不会传到该子控件来了。
  •  
  • 这里要注意是逐层,也就是说每层(指的只是ViewGroup)的拦截器还是可以拦截到后续的ACTION_MOVE与ACTION_UP。如果后续的ACTION_MOVE与ACTION_UP被某层的拦截器拦截,则后续的事件将不会再传递给之前处理onTouchEvent的子控件,而是逐层传递给由拦截消息的这个控件的onTouchEvent函数进行处理,并且会向其之前接收事件的子控件发送一个ACTION_CANCEL,表示后续事件被取消了。

参考:https://www.jianshu.com/p/35a8309b9597

举例子

布局结构和ontouch事件的传递顺序

长这样:

注:XML的绘制顺序是从外层到内层,同一层从上到下,绘制迟的覆盖绘制早的;在这里的XML,无论是否把MyButton写在TextView后面,由于MyButton显示优先级高于TextView所以显示在TextView上,并且获取事件优先级也高于TextView。

1和2点的逻辑示意图

1.点白色部分FrameLayout:Frame的OntouchEvent返回false表示不消费事件;ACTION_UP就不传给他了

引用图片:https://blog.csdn.net/morgan_xww/article/details/9372285

2.点蓝色部分RelativeLayout:RelativeLayout的OntouchEvent返回false表示不消费事件;ACTION_UP不传给他了

由于触摸事件都是连续的。如果ACTION_DOWN传递到子控件,而子控件的onTouchEvent返回值是false,即没有处理该ACTION_DOWN事件,则后续的ACTION_MOVE和ACTION_UP就不会传到该子控件来了。ACTION_DOWN事件一直传递到了RelativeLayout,但是最终是被MainActivity的onTouchEvent处理的,而从而导致ACTION_MOVE和ACTION_UP只传递到了MainActivity,最终也是由MainActivity处理的情况。

引用图片:https://blog.csdn.net/morgan_xww/article/details/9372285

3.点淡绿色部分MyTextView:MyTextView返回true;ACTION_UP继续传给他

逻辑示意

引用图片:https://blog.csdn.net/morgan_xww/article/details/9372285

4.点淡蓝色部分MyButton:MyButton返回false;MyTextView返回true; ACTION_UP不再通过MyButton

由于触摸事件都是连续的。如果ACTION_DOWN传递到子控件,而子控件的onTouchEvent返回值是false,即没有处理该ACTION_DOWN事件,则后续的ACTION_MOVE和ACTION_UP就不会传到该子控件来了。ACTION_DOWN事件一直传递到了MyButton,但是最终是被MyTextView的onTouchEvent处理的,而从而导致ACTION_MOVE和ACTION_UP只传递到了MyTextView,最终也是由MyTextView处理而跳过MyButton情况。

参考这个 

猜你喜欢

转载自blog.csdn.net/lance666/article/details/105548079
今日推荐