• Android开发艺术探索笔记——View(二)


    Android开发艺术探索笔记——View(二)

    View的事件分发机制

    学习资料:
    1.Understanding Android Input Touch Events System Framework
    2.Managing Touch Events in a ViewGroup
    3.Android事件传递机制
    4.Input Events
    5.Mastering the Android Touch System
    6.MotionEvent

    MotionEvent(运动事件)的传递规则

    用户每次触摸屏幕都被包装成了MotionEvent(运动事件)对象

    属性有:

    • 动作码(action code),如ACTION_DOWN,ACTION_UP等等,用于描述用户当前的动作。
    • 触摸的横纵坐标
    • 其它信息,如压力,大小以及方向等等。

    View的事件分发,就是对MotionEvent事件的分发过程。

    事件分发的三个重要方法:

       //用于分发事件(dispatch touch event),要么将事件向下传递到目标View,要么交由自己处理。
       //返回true表示自己处理
       public boolean dispatchTouchEvent (MotionEvent event)
       
       //用于拦截事件(intercept touch event),ViewGroup中有,View中没有这个方法。
       public boolean onInterceptTouchEvent (MotionEvent event)
       
       //用于处理事件
       public boolean onTouchEvent (MotionEvent event)
    

    三个方法的关系可用如下伪代码描述:

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

    viewTouchEvent

    View的onTouchListener的优先级比onTouchEvent方法的高。

    运动事件的传递顺序:

    Activity-->Window-->View
    

    下面是将ViewdispatchTouchEvent()方法设置断点后,点击ImageView的调试过程:

    viewTouchEvent

    能清楚地看到事件的传递过程和顺序。

    若View的onTouchEvent()方法返回false,则会调用它的父View的onTouchEvent()方法,依此类推,若调用顺序上的所有View都不处理这个事件,则这个事件会最终传递给Activity的onTouchEvent()方法。

    View的事件分发机制类似于互联网公司的工作流程:

     新任务:
     CEO-->产品经理-->CTO-->开发小组组长-->程序员
     
     由上至下一级一级分发任务(dispatchTouchEvent),如果是自己的任务(onInterceptTouchEvent)
     ,则拦截自己处理(onTouchEvent),反之,则交由下级分发(child.dispatchTouchEvent)。
     
     如果事情搞不定,就一级一级向上抛(parent.onTouchEvent):
     程序员-->开发组长-->CTO-->产品经理-->CEO
     
    

    事件传递机制的一些结论:

    • 1.事件序列:从手指接触屏幕到手指离开屏幕的过程,ACTION_DOWN-->ACTION_MOVE-->...-->ACTION_MOVE-->ACTION_UP
    • 2.一个事件序列只能被一个View拦截且消费。
    • 3.ViewGroup默认不拦截事件。源码中ViewGroup的onInterceptTouchEvent()方法默认返回false
    • 4.View没有onInterceptTouchEvent()方法
    • 5.事件传递是由外向内(由上至下)的。事件先传递给父元素,然后再由父元素分发给子元素。通过 requestDisallowInterceptTouchEvent()方法可以在子元素中干预父元素的事件分发过程。

    事件分发源码解析

    Activity对事件的分发过程

    • 1.点击事件首先传递给Activity,然后由ActivitydispatchTouchEvent()方法进行事件的分发。Activity会将事件交由window进行分发。
    //Activity源码
     ...
     /*
      * Activity的dispatchTouchEvent方法
      */
     public boolean dispatchTouchEvent(MotionEvent ev) {
            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
                onUserInteraction();
            }
            //Activity交由window进行事件分发
            if (getWindow().superDispatchTouchEvent(ev)) {
                return true;
            }
            return onTouchEvent(ev);
        }
    
    • 2.Window将事件传递给DecorView(即ContentView的父View,可通过Activity.getWindow().getDecorView()方法获取)。而Window类是抽象类,superDispatchTouchEvent()方法是抽象方法。
    //Window类是抽象类
    public abstract class Window {
    ...
    //window的superDispatchTouchEvent方法是抽象方法
    public abstract boolean superDispatchTouchEvent(MotionEvent event);
    ...
    }
    

    而PhoneWindow类是Window类的唯一实现类。

    
    public class PhoneWindow extends Window implements MenuBuilder.Callback {
    ...
      @Override
        public boolean superDispatchTouchEvent(MotionEvent event)       { 
        //PhoneWindow直接将事件交友DecorView处理
        return mDecor.superDispatchTouchEvent(event);
        }
     ...
     }
    

    可以看到PhoneWindow类在实现抽象方法superDispatchTouchEvent时,直接将事件交由DecorView处理。

  • 相关阅读:
    「APIO2017」商旅
    【CQOI2017】小Q的表格
    【HNOI2016】树
    【NOI2018模拟】Yja
    测试
    Loj #6073.「2017 山东一轮集训 Day5」距离
    「AHOI / HNOI2017」影魔
    Loj 6068. 「2017 山东一轮集训 Day4」棋盘
    【SDOI2014】向量集
    远程服务器安装nginx
  • 原文地址:https://www.cnblogs.com/JohnTsai/p/5739949.html
Copyright © 2020-2023  润新知