Android学习笔记之事件分发机制(二)

来源:互联网 发布:绘画 知乎 编辑:程序博客网 时间:2024/06/06 00:38

说明:关于安卓的事件分发机制总共有三篇,第一篇和第二篇我尝试着通过调试信息向大家说明一些情况,但相信我,越看你会觉得越乱.这跟事件分发机制的复杂有一定的关系.第一篇和第二篇其实只是在给最后一篇做铺垫而已,在最后一篇中我会借助源码和前面的铺垫尽可能的向你展示所有的细节.

前言

在 Android学习笔记之事件分发机制(一)中,由于写得有点急,没有认真对调试信息进行分析,后来在分析源码的过程中才发现自己写错了,现在已经修改好了.给大家造成了误导,在这里说声抱歉.
之前不想让篇幅太长,还有些东西没写完.在这篇博文中,继续上一篇的脚步,进一步对事件分发机制进行学习.

进一步

之前我们只是对一个按钮的触碰事件进行分析,但是你有没有想过这些事件是怎么传递到按钮上来的呢?所以今天要做的实验就是增加一个自定义Layout(嵌套着CustomButton)和重写Activity中相应的方法.

CustomLayout.java

public class CustomLayout extends LinearLayout {    private static final String TAG = "event";    public CustomLayout(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.d(TAG, "CustomLayout---dispatchTouchEvent---action down");                break;            case MotionEvent.ACTION_MOVE:                Log.d(TAG, "CustomLayout---dispatchTouchEvent---action move");                break;            case MotionEvent.ACTION_UP:                Log.d(TAG, "CustomLayout---dispatchTouchEvent---action up");                break;        }        return super.dispatchTouchEvent(event);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.d(TAG, "CustomLayout---onTouchEvent---action down");                break;            case MotionEvent.ACTION_MOVE:                Log.d(TAG, "CustomLayout---onTouchEvent---action move");                break;            case MotionEvent.ACTION_UP:                Log.d(TAG, "CustomLayout---onTouchEvent---action up");                break;        }        return super.onTouchEvent(event);    }}

MainActivity.java

findViewById(R.id.layout).setOnTouchListener(new View.OnTouchListener() {    @Override    public boolean onTouch(View v, MotionEvent event) {        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                Log.d(TAG, "CustomLayout---onTouch---action down");                break;            case MotionEvent.ACTION_MOVE:                Log.d(TAG, "CustomLayout---onTouch---action move");                break;            case MotionEvent.ACTION_UP:                Log.d(TAG, "CustomLayout---onTouch---action up");                break;        }        return false;    }}); @Overridepublic boolean onTouchEvent(MotionEvent event) {    switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            Log.d(TAG, "Activity---onTouchEvent---action down");            break;        case MotionEvent.ACTION_MOVE:            Log.d(TAG, "Activity---onTouchEvent---action move");            break;        case MotionEvent.ACTION_UP:            Log.d(TAG, "Activity---onTouchEvent---action up");            break;    }    return super.onTouchEvent(event);}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {    switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            Log.d(TAG, "Activity---dispatchTouchEvent---action down");            break;        case MotionEvent.ACTION_MOVE:            Log.d(TAG, "Activity---dispatchTouchEvent---action move");            break;        case MotionEvent.ACTION_UP:            Log.d(TAG, "Activity---dispatchTouchEvent---action up");            break;    }    return super.dispatchTouchEvent(event);}

注意:如果在onTouch中返回true的话,是看不到后面onTouchEvent的执行的.

点击一下按钮,可以看到:

调试信息

dispatchTouchEvent的执行顺序是这样的: Activity -> Layout -> View. 这样也很好理解,事件从Activity开始分发,然后从xml的最外层往最内层去传.

不知道大家有没有发现,我们写的有几个方法没有被执行到.
MainActivity: onTouchEvent没有被执行到.
CustomLayout: onTouchonTouchEvent都没有被执行到.
CustomButton: 所有方法都被执行到了.

先来分析这个CustomLayout.在第一篇中我说到了,View的各个方法执行顺序是这样的: dispatchTouchEvent -> onTouch -> onTouchEvent -> onClick.Layout本身是ViewGroup,继承自View,按道理来说应该是要先执行Layout的各个方法,然后有可能再传到子View中的,但从结果来看,它是直接跳到子View去执行的.有一种猜想就是事件先分发到子View中,有机会再传给Layout,但这和dispatchTouchEvent的执行顺序相违背.所以这种猜想不成立.

查了一下资料,才发现ViewGroup还有另外一个方法

@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {    return super.onInterceptTouchEvent(ev);}

看一下它的源码,只有一行.

public boolean onInterceptTouchEvent(MotionEvent ev) {    return false;}

从名字上可以看出这是用来判断是否截获事件的.我们试着让它返回true,看看会发生什么.

调试信息

是不是跟第一篇博文的结果很像了,但又有一些不同.

  • 多了一个onInterceptTouchEvent.
  • 惊喜的发现MainActivity的onTouchEvent也被执行到了.
  • action up直接就是跳过了CustomLayout中的方法.

onInterceptTouchEvent返回true的时候,事件被当前ViewGroup自己处理,不再往下分发事件.此时它自己的角色就是一个View了,执行View中相应的方法.

接着,将CustomLayout.java中onTouchEvent的返回值super.onTouchEvent(event)改为true,再看一下结果

调试信息

有没有发现MainActivity的onTouchEvent又没了,而CustomLayout相应的方法又被执行了!我相信看到这里,你已经快崩溃了.如果只通过调试信息来做判断的话是很难得出正确结论的.所以这一部分还是留待下一次通过源码来分析吧.到时候再回过头来看就会觉得很清楚了,甚至遇到相似的问题不用再去看源码可以自己推导出来了.

End

这两篇博文看到现在,可能还是有很多人没看懂.但这两篇其实只是在为最后的源码分析做铺垫而已.同时,写了这两篇博文也让我自己梳理了一遍.相信我,最后一篇会尽可能的让大家明白的.

0 0
原创粉丝点击