Android 事件分发学习

1,560 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

MotionEvent

事件介绍
ACTION_DOWN手指初次接触到屏幕出发
ACTION_MOVE手指在屏幕上滑动时触发,会多次触发
ACTION_UP手指离开屏幕时触发
ACTION_CANCLE事件被上层拦截时触发

事件序列主要有以下两种组成

  1. ACTION_DOWN->ACTION_UP
  2. ACTION_DOWN->许多个ACTION_MOVE>ACTION_UP

image.png

View继承关系

image.png

image.png 事件分发的大概流程可以这样来描述:Activity -> PhoneWindow ->DecorView(DecorView其实就是一种ViewGroup) ->View

  • ViewGroup 先要进行分发,再进行事件处理
  • View 只能进行事件处理

image.png 事件分发需要的三个重要方法来共同完成: public boolean dispatchTouchEvent(event):用于进行点击事件的分发 public boolean onInterceptTouchEvent(event):用于进行点击事件的拦截 public boolean onTouchEvent(event):用于处理点击事件 三个函数的参数均为event,即上面所说的3种类型的输入事件,返回值均为boolean 类型

    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean consume = false;//事件是否被消费
        if (onInterceptTouchEvent(ev)){//调用onInterceptTouchEvent判断是否拦截事件
            consume = onTouchEvent(ev);//如果拦截则调用自身的onTouchEvent方法
        }else{
            consume = child.dispatchTouchEvent(ev);//不拦截调用子View的dispatchTouchEvent方法
        }
        return consume;//返回值表示事件是否被消费,true事件终止,false调用父View的onTouchEvent方法
    }

事件分发-ACTION_DOWN的大致流程

image.png

  • 首先是要说明的是,上图的分析仅仅只限于对ACTION_DOWN的分析
  • U形图从上到下可以分为三层,分别是Activity层,ViewGroup层,和View层
  • 事件的开始分发是从右上角的大红色的箭头开始传输的
  • 线上的false/ture/super 分别表示的是箭头起点函数的返回值:return false/return ture/return supperxxx(调用父类的返回)
  • 箭头指向消费,表示该事件就到此为止,不会再往下传或往上一级传
  • 如果事件在分发的过程中一直不被消费,那么整个分发的过程看起来就是一个U形的结构
  • 图中只是说明了activity中只有一个ViewGroup的情况,实际操作中可能会有View ViewGroup多层嵌套的情况,原理也是这个原理,大同小异。
小结
  • 对于activity来说dispatchTouchEvent中无论是返回ture/false都会将事件消费,即不会再往下面传播,只有return super的时候才会传到 ViewGroup()
  • 对于dispatchTouchEvent和onTouchEvent来说return false会把该事件交给父容器来处理
  • 对于onInterceptTouchEvent来说返回false,顾名思义,该viewGroup将不会拦截该事件,这个事件就可以继续向下传播了,如果onInterceptTouchEvent返回ture就表明该ViewGroup将会拦截该事件,事件将会交给该组件的onTouchEvent来处理,事件也就不会再往下面的组件分发了
  • 对于onTouchEvent来说对于传入他的事件,如果返回ture就代表该事件已经被消费,则流程就终止,如果返回false,那么就代表该事件将不会由他处理,将会将给父容器的onTouchEvent来处理。
  • 每个ViewGroup每次在做分发的时候,问一问拦截器要不要拦截(也就是问问自己这个事件要不要自己来处理)如果要自己处理那就在onInterceptTouchEvent方法中 return true就会交给自己的onTouchEvent的处理,如果不拦截就是继续往子控件往下传。默认是不会去拦截的,因为子View也需要这个事件,所以onInterceptTouchEvent拦截器return super.onInterceptTouchEvent()和return false是一样的,是不会拦截的,事件会继续往子View的dispatchTouchEvent传递。
  • 看下ViewGroup 的dispatchTouchEvent,之前说的return true是终结传递。return false 是回溯到父View的onTouchEvent,然后ViewGroup怎样通过dispatchTouchEvent方法能把事件分发到自己的onTouchEvent处理呢,return true和false 都不行,那么只能通过Interceptor把事件拦截下来给自己的onTouchEvent,所以ViewGroup dispatchTouchEvent方法的super默认实现就是去调用onInterceptTouchEvent
  • 那么对于View的dispatchTouchEvent return super.dispatchTouchEvent()的时候呢事件会传到哪里呢,很遗憾View没有拦截器。但是同样的道理return true是终结。return false 是回溯会父类的onTouchEvent,怎样把事件分发给自己的onTouchEvent处理呢,那只能return
  • super.dispatchTouchEvent,View类的dispatchTouchEvent()方法默认实现就是能帮你调用View自己的onTouchEvent方法的。

ACTION_MOVE 和ACTION_UP事件的处理

ACTION_MOVE和ACTION_UP就会从上往下(通过dispatchTouchEvent)做事件分发往下传,就只会传到这个控件,不会继续往下传,如果ACTION_DOWN事件是在dispatchTouchEvent消费,那么事件到此为止停止传递,如果ACTION_DOWN事件是在onTouchEvent消费的,那么会把ACTION_MOVE或ACTION_UP事件传给该控件的onTouchEvent处理并结束传递。