Android view 事件分发

原创
2019/02/13 22:35
阅读数 85

前言

我们在学习View的时候,不可避免会遇到事件的分发,而往往遇到的很多滑动冲突的问题都是由于处理事件分发时不恰当所造成的。因此,深入了解View事件分发机制的原理,对于我们来说是很有必要的。由于View事件分发机制是一个比较复杂的机制。因为我们平时所接触的View都不是单一的View,往往是由若干个ViewGroup组合而成,而事件的分发又是由ViewGroup传递到它的子View的,所以我们先从ViewGroup的事件分发说起。注意,以下源码取自安卓5.0(API 21)。

三个重要方法

public boolean dispatchTouchEvent(MotionEvent ev)

该方法用来进行事件的分发,即无论ViewGroup或者View的事件,都是从这个方法开始的。

public boolean onInterceptTouchEvent(MotionEvent ev)

表示是否拦截当前事件,返回true表示拦截,如果拦截了事件,那么将不会分发给子View。比如说:ViewGroup拦截了这个事件,那么所有事件都由该ViewGroup处理,它内部的子View将不会获得事件的传递。(但是ViewGroup是默认不拦截事件的,这个下面会解释。)注意:View是没有这个方法的,也即是说,继承自View的一个子View不能重写该方法,也无需拦截事件,因为它下面没有View了,它要么处理事件要么不处理事件,所以最底层的子View不能拦截事件。

public boolean onTouchEvent(MotionEvent ev)

这个方法表示对事件进行处理,在dispatchTouchEvent方法内部调用,如果返回true表示消耗当前事件,如果返回false表示不消耗当前事件。

以上三个方法非常重要,贯穿整个View事件分发的流程,它们的关系可以用如下伪代码呈现:

public boolean dispatchTouchEvent(MotionEvent ev){
    boolean handle = false;
    if(onInterceptTouchEvent(ev)){
        handle = onTouchEvent(ev);
    }else{
        handle = child.dispatchTouchEvent(ev);
    }
    return handle;
}

由以上伪代码可得出如下结论:如果一个事件传递到了ViewGroup处,首先会判断当前ViewGroup是否要拦截事件,即调用onInterceptTouchEvent()方法;如果返回true,则表示ViewGroup拦截事件,那么ViewGroup就会调用自身的onTouchEvent来处理事件;如果返回false,表示ViewGroup不拦截事件,此时事件会分发到它的子View处,即调用子View的dispatchTouchEvent方法,如此反复直到事件被消耗掉。

 

view的事件分发

几点说明

  • 主要两个方法 dispatchTouchEventonTouchEvent
  • dispatchTouchEvent 结果返回false会阻断事件传递,返回true会消费掉这次事件,继续下一个事件处理,直到事件处理完。
  • 拦截click事件可以修改onTouch返回true
  • 不可点击的控件默认只有Down的Touch事件,要想有Move和Up事件,必须修改onTouch返回true或者设置clickable为true

viewGroup的事件分发

几点说明

  • 主要方法比View多一个onInterceptTouchEvent,拦截touch事件
  • 事件分发是先从viewGroup,然后再到子View
  • 如果onInterceptTouchEvent返回true,就拦截掉事件,没有子View处理事件的机会了,会走到ViewGroup自身事件处理,基本在onTouch中处理,跟View一样,返回true,继续下个事件,返回false,阻断事件传递
  • 如果点击区域不在子View上,跟onInterceptTouchEvent返回true处理一样,否则会遍历子View,判断是Visible就把事件交给子View处理(注意:这里有模糊点,后面会说
  • 如果子View dispatchTouchEvent 返回true,如果子View clickable为true,返回就肯定是true,就会阻断流程。这样父ViewGroup就不能处理事件了
  • 如果子View dispatchTouchEvent 返回false就会执行所有字View的dispatchTouchEvent,并继续父ViewGroup的事件处理。
  • 让子View dispatchTouchEvent 返回false,只能是clickable为false,这样子View就会阻断事件传递,也就终止了整个事件传递。即子View和父ViewGroup只有Down事件处理

结合上面的理解,我们再来看看Touch事件传递机制流程图

参考

https://blog.csdn.net/suyimin2010/article/details/80958205

https://www.jianshu.com/p/bccf79bd5b5d

 

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部