美文网首页
何止学习Android事件分发机制

何止学习Android事件分发机制

作者: 何止搬砖工 | 来源:发表于2020-07-11 22:34 被阅读0次

    一、安卓UI层级

    image.png

    Activity的结构为:Activity -> PhoneWindow -> DecorView -> ContentView -> ... -> View

    二、安卓UI事件分发流程

    1.安卓UI的View是树形结构的,基于这样的结构,事件可以进行有序的分发。

    事件收集之后最先传递给 Activity, 然后依次向下传递。根据Activity的内部结构也可以看出,事件分发的流程:Activity -> PhoneWindow -> DecorView -> ContentView -> ... -> View。如果View没有消费事件,则会回传。流程如下:View-> ... ->ContentView -> DecorView -> PhoneWindow ->Activity。

    总体流程来说,整个流程是遵循责任链模式。上层View既可以直接拦截该事件,自己处理,也可以先询问(分发给)子View,如果子View需要就交给子View处理,如果子View不需要还能继续交给上层View处理。既保证了事件的有序性,又非常的灵活。

    2.事件分发、拦截与消费

    image.png

    这三个方法,通过返回 true 和 false 来控制事件传递的流程.
    三个方法:
    dispatchTouchEvent(事件分发)
    onInterceptTouchEvent(事件拦截)
    onTouchEvent(事件回传:从View开始,逐级回传)

    三、实战

    1.创建安卓工程,布局如下

    <?xml version="1.0" encoding="utf-8"?>
    <com.example.customer.view.View.RootView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:background="#4E5268"
        android:layout_margin="20dp"
        tools:context="com.example.customer.view.MainActivity">
    
        <com.example.customer.view.View.ViewGroupA
            android:background="#95C3FA"
            android:layout_width="200dp"
            android:layout_height="200dp">
    
            <com.example.customer.view.View.View1
                android:background="#BDDA66"
                android:layout_width="130dp"
                android:layout_height="130dp"/>
    
        </com.example.customer.view.View.ViewGroupA>
    
        <com.example.customer.view.View.View2
            android:layout_alignParentRight="true"
            android:background="#BDDA66"
            android:layout_width="80dp"
            android:layout_height="80dp"/>
    
    </com.example.customer.view.View.RootView>
    

    2.布局结构图如下:

    image.png

    3.触发事件分析:

    按下view1,不放开

    事件分发流程如下:
    MainActivity: dispatchTouchEvent ->
    RootView: dispatchTouchEvent ->
    RootView: onInterceptTouchEvent ->
    ViewGroupA: dispatchTouchEvent->
    ViewGroupA: onInterceptTouchEvent->
    View1: dispatchTouchEvent->
    View1: onTouchEvent->
    ViewGroupA: onTouchEvent->
    RootView: onTouchEvent->
    MainActivity: onTouchEvent->


    image.png

    按下view1后,放开

    image.png

    事件分发流程如下:
    MainActivity: dispatchTouchEvent ->
    RootView: dispatchTouchEvent ->
    RootView: onInterceptTouchEvent ->
    ViewGroupA: dispatchTouchEvent->
    ViewGroupA: onInterceptTouchEvent->
    View1: dispatchTouchEvent->
    View1: onTouchEvent->
    ViewGroupA: onTouchEvent->
    RootView: onTouchEvent->
    MainActivity: onTouchEvent->
    MainActivity: dispatchTouchEvent (Action:ACTION_UP)->
    MainActivity: onTouchEvent (Action:ACTION_UP)
    注意:MotionEvent. ACTION_UP事件在MotionEvent.ACTION_DOWN结束后触发。

    在RootView增加事件(MotionEvent.ACTION_DOWN)拦截,按下view1后,放开

      @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.d(TAG,"onInterceptTouchEvent Action:"+MotionEvent.actionToString(ev.getAction()));
            if (ev.getAction() == MotionEvent.ACTION_DOWN){
                return true;
            }else {
                return super.onInterceptTouchEvent(ev);
            }
    
        }
    
    image.png

    从打印结果来看,(MotionEvent.ACTION_DOWN)事件不再往下传,在RootView接收到后回传给MainActivity。

    注意:onInterceptTouchEvent() 返回true表示拦截、返回false表示不拦截,不拦截时,跟正常的流程一样。

    四、View 事件相关的各个方法调用顺序

    onTouchListener > onTouchEvent > onLongClickListener > onClickListener

    1、onTouchEvent返回true时,代表消费事件,则事件不回传。

    image.png

    2、onTouchEvent返回false时,代表没有消费事件,则事件回传。

    image.png

    五、核心要点

    事件分发原理: 责任链模式,事件层层传递,直到被消费。
    View 的 dispatchTouchEvent 主要用于调度自身的监听器和 onTouchEvent。
    View的事件的调度顺序是 onTouchListener > onTouchEvent > onLongClickListener > onClickListener 。
    不论 View 自身是否注册点击事件,只要 View 是可点击的就会消费事件。
    事件是否被消费由返回值决定,true 表示消费,false 表示不消费,与是否使用了事件无关。
    ViewGroup 中可能有多个 ChildView 时,将事件分配给包含点击位置的 ChildView。
    ViewGroup 和 ChildView 同时注册了事件监听器(onClick等),由 ChildView 消费。
    一次触摸流程中产生事件应被同一 View 消费,全部接收或者全部拒绝。
    只要接受 ACTION_DOWN 就意味着接受所有的事件,拒绝 ACTION_DOWN 则不会收到后续内容。
    如果当前正在处理的事件被上层 View 拦截,会收到一个 ACTION_CANCEL,后续事件不会再传递过来。

    相关文章

      网友评论

          本文标题:何止学习Android事件分发机制

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