美文网首页
事件分发机制

事件分发机制

作者: 夜沐下的星雨 | 来源:发表于2020-06-06 10:25 被阅读0次

1.简介

事件分发是我们触摸屏幕产生的一系列事件,系统接收到这些事件后怎么去处理这些事件的逻辑,叫事件分发。事件分发的本质就是事件(MotionEvent)传递到某个具体的View & 处理的整个过程

事件分发的对象是谁?点击事件(Touch事件)
定义:当用户触摸屏幕时(View 或 ViewGroup派生的控件),将产生点击事件(Touch事件)
Touch事件的相关细节(发生触摸的位置、时间等)被封装成MotionEvent对象

2. 事件分类

事件类型.PNG
特别说明:从手指接触屏幕 至 手指离开屏幕,这个过程产生的一系列事件
一般情况下,事件列都是以DOWN事件开始、UP事件结束,中间有无数的MOVE事件,如下图:
事件.PNG

3.涉及对象和方法

事件的分发涉及三个对象

Activity ViewGroup View

当有一个点击事件,从actvity 传到viewGroup,再传到view层级,有外向内,层层传递。

类型.PNG

Activity 作为原始的事件分发者,如果 Activity 拦截了事件会导致整个屏幕都无法响应事件。因此一般不做处理。

ViewGroup 有点特殊,它多了一个事件拦截的方法onInterceptTouchEvent,它的返回值确定了是调用子View的 dispatchTouchEvent还是自身的 onTouchEvent。如果没有拦截就交给子类view处理。如果拦截,就交给自身的onTouchEvent()处理;

View :作为事件传递的最末端,要么消费掉事件,要么不处理进行回传。view的调度顺序为 onTouchListener > onTouchEvent > onLongClickListener >onClickListener

事件分发主要涉及三个方法:

dispatchTouchEvent-事件分发;在三个对象都有这个方法
onInterceptTouchEvent 事件拦截;只有在viewgroup 里才有事件的拦截
onTouchEvent-事件消费。在三个对象都有这个方法

事件方法.PNG

4.事件分发流程

事件流程.PNG
事件分发.PNG

上图分析

  1. Activity
    dispatchTouchEvent(MotionEvent ev) -- 事件分发
    ①返回true 直接消费掉 ,没有分发;
    ②返回false,不消费,但是触摸事件不做处理;
    ③只有返回super.dispatchTouchEvent(ev)事件才会向子view分发,其实是调用了PhoneWindow的superDispatchTouchEvent(),进而调用了DecorView的superDispatchTouchEvent,里面又调用了super.dispatchTouchEvent(),而DecorView是一个FrameLayout
    onTouchEvent(MotionEvent event) --事件处理
    ①返回false和默认(super.onTouchEvent(event)),不做处理;
    ②返回true,消费事件
  1. ViewGroup
    dispatchTouchEvent(MotionEvent ev) -- 事件分发
    ①返回true 事件被消费了, 事件未分发
    ②返回false 事件未分发,事件传递到父容器的onTouchEvent()
    ③只有返回super.dispatchTouchEvent(ev),事件才会向下走,里面会调用onInterceptTouchEvent()
    onInterceptTouchEvent(MotionEvent ev) -- 事件拦截
    ①返回true,事件拦截,调用自己的onTouchEvent()
    ②返回false,事件未拦截,分发给了子view
    ③super.onInterceptTouchEvent(ev)与返回false效果一样
    onTouchEvent(MotionEvent event) --事件处理
    ①返回false和super.onTouchEvent(event)事件不消费,事件传递给父容器
    ②返回true,事件会被消费
  1. View
    dispatchTouchEvent(MotionEvent ev) -- 事件分发
    因为它最小,没有子view,所以这个方法其实没有进行分发的能力
    ①返回true,事件被消费,
    ②返回false ,事件传递到父容器的onTouchEvent()
    ③只有返回super.dispatchTouchEvent(ev),事件才会向下走,里面会调用自己 onTouchEvent()
    onTouchEvent(MotionEvent event) --事件处理
    ①返回false和super.onTouchEvent(event)事件不消费,事件传递给父容器
    ②返回true,事件会被消费

5.点击事件触发的位置及拦截

在onTouchEvent() 方法中MotionEvent.ACTION_UP中会调用performClick(),
performClick()中会调用onClick()
拦截点击事件:
在父容器中重写 onInterceptTouchEvent(MotionEvent ev) ,
返回true,会走父容器的onTouchEvent()方法

6.滑动事件冲突

父容器想获取左右滑动事件,子view想获取垂直滑动事件(如Viewpager中有ListView),都想获取事件,怎么办?
思路:可以进行选择性的拦截事件,当水平滑动的距离大于垂直滑动的距离时,拦截事件

  @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //选择性的进行拦截,当水平滑动距离大于垂直滑动距离时 ,拦截
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownX = ev.getX();
                mDownY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = ev.getX();
                float moveY = ev.getY();
                //水平和垂直的滑动距离(绝对值)
                float dx = Math.abs(moveX - mDownX);
                float dy = Math.abs(moveY- mDownY);
                if (dx>dy){
                    return true;
                }
                break;
        }

        return false;//不拦截
    }

getX()和getY():由这两个函数获得的x,y值是相对的坐标值,相对于父容器坐标。
getRawX()和getRawY():有这两个函数获得的x,y值是绝对坐标,是相对于屏幕的。

坐标.PNG

相关文章

网友评论

      本文标题:事件分发机制

      本文链接:https://www.haomeiwen.com/subject/xzfgzhtx.html