【Android View事件(二)】详解事件分发机制

【本文出自大圣代的技术专栏 http://blog.csdn.net/qq_23191031
【转载烦请注明出处,尊重他人劳动成果就是对您自己的尊重】

相关文章

1.《【Android View触摸事件(一)】Android常用触控类分析:MotionEvent 、 ViewConfiguration、VelocityTracker》
2.《【Android 控件架构】详解Android控件架构与常用坐标系》

一,前言

Android事件分发机制不仅仅是核心知识更是难点,这对于不少初学者甚至是中级开发者来说都会觉得困惑。另外,View的另一大难题就是滑动冲突,解决它的方法就需要掌握事件分发机制作为理论基础,因此掌握好View的事件分发机制是十分重要的。

本篇文章将以图文结合的方式,深入介绍View的事件分发机制。而后面的文章我将会详细分析View 的滑动以及滑动冲突,敬请期待。

注: 图片不清楚的可以点击图片,鼠标右键,在新的标签中打开。

二,事件分发机制存在的原因

《Android常用触控类分析》一文中我们详细学习了MotionEvent的常用方法和属性,总的说来Android中的触摸事件其实就是一个动作类型+坐标。但是通过《详解Android控件架构与常用坐标系》一文我们知道,Android的View结构是树状的,也就是说,View可以放在ViewGroup里面来实现不同的样式。那么问题来了,View放在一个ViewGroup中,这个ViewGroup又放在另外一个ViewGroup里面,甚至还有可能继续嵌套,一层层地叠起来。可我们的触摸事件就一个,到底应该分给谁呢?对于同一个事件,子View与父ViewGroup都有可能想要进行处理,为了协调这个过程,就产生了事件分发机制。

三,分析的对象是谁

在介绍点击事件之前,首先我们要明白这里分析的对象就是MotionEvent,我在《Android常用触控类分析》中对于MotionEvent有着详细的介绍。此处不再赘述。所谓点击事件的分发,其实就是对于MotionEvent事件分发的过程。即当一个MotionEvent产生了以后,系统需要将这个事件传递到一个具体的View上,而这个传递过程就是分发。此过程中涉及到三个很重要的方法来共同实现:dispathTouchEventonInterceptTouchEvent,onTouchEvent。他们分别代表着分发、拦截、处理。

四,事件分发规则与方法介绍

在《Android群英传》中对于事件分发规则有着一段生动的描述,摘取一段分享给你。

首先,请想象一下生活中非常常见的场景:假设你所在的公司,又一个总经理,级别最高,他下面有一个部长,级别次之;最低层,就是干活的你,没有级别(手下无人)。现在董事会交给总经理一项任务,总监理将这个任务部署给了部长,部长又把任务安排给了你。

接下来我们看看整个过程中事件的传递是怎么样的:

那么在事件分发机制中:
董事长:相对于Activity
总经理:相当于最外层的ViewGroup,在此我们称他为 ViewGroupA。
部长:中间层的ViewGroup,称为ViewGroupB。
干活的你:最底层的View

为了充分说明,设计如下场代码实例:

本实例的布局与涉及类如下图所示:

image.png

布局代码

    <com.example.im_ds.myapplication.MyViewGroupA
        android:layout_width="300sp"
        android:layout_height="400sp"
        android:background="@android:color/holo_red_light">

        <com.example.im_ds.myapplication.MyViewGroupB
            android:layout_width="250sp"
            android:layout_height="300sp"
            android:background="@android:color/holo_blue_light">

            <com.example.im_ds.myapplication.MyView
                android:layout_width="200sp"
                android:layout_height="200sp"
                android:background="@android:color/holo_orange_light" />
        </com.example.im_ds.myapplication.MyViewGroupB>


    </com.example.im_ds.myapplication.MyViewGroupA>

为方便 ViewGroup直接继承了 RelativeLayout,而View再次继承了TextView(TextView默认是不会响应事件的)。代码比较简单,只是重写了事件传递所涉及的方法、在点击的时候打印Log。

对于ViewGroup而言,重写了以下三个方法。

      @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            Log.d("TAG", "MyViewGroupA  dispatchTouchEvent   ");
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            Log.d("TAG", "MyViewGroupA  onInterceptTouchEvent  ");
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Log.d("TAG", "MyViewGroupA  onTouchEvent   ");
        }
        return super.onTouchEvent(event);
    }

对于View,重写如下所示的两个方法

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Log.d("TAG", "MyView  dispatchTouchEvent  ");
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            Log.d("TAG", "MyView  onTouchEvent   " );
        }
        return super.onTouchEvent(event);
    }

场景一 “这个工作没人愿意接”

在未做任何其他处理的情况下,点击MyView得到以下日志:

image.png

我们将这个过程整理成图:

整个事件传递的过程一目了然,作为底层员工的你(MyView),在没有人愿意接的情况下,你不得不接手工作

事件传递过程中的返回值很容易理解: ture,拦截,不继续,false,不拦截,继续流程,默认情况下返回值都是 false。

值得注意的是在事件开发工作中,虽然 dispatchTouchEvent是第一步但是我们很少会改写它,所以下面的场景中我们只关心onInterceptTouchEvent即可

场景二:“总经理良心发现,接手工作”

假设总经理(MyViewGroupA)发现这个任务太简单了,觉得他自己就能做,完全没有必须找下属就去。此时总经理就自行拦截了(onInterceptTouchEvent)任务,既让MyViewGroupAonInterceptTouchEvent返回 true,运行一下看看结果是怎么样的呢

和我们的设想一样,总经理(MyViewGroupA)把活都接手了,后面的人当然就没有事情做了。

同样的,假设我们的部长(MyViewGroupB)也做了一回好人,即让部长(MyViewGroupB)使用 onInterceptTouchEvent方法返回true,把事件拦截下来:

五,传递处理与方法介绍

我相信大家对于事件分发的过程已经很清楚了,下面我们再看看事件的处理的过程。
事件处理的返回值也类型:ture,处理,不用审核了;false 处理不了,交给上级。

场景一 “这个工作没人愿意接”

此时底层得你没有办法在分配了只能选择干活。但是到底能不能干还得再议:

1.1 能干

此时皆大欢喜,你把事件消费了,不在传递。

1.2 不能干

有一天你(MyView)了,你的领导么只能一层一层反应,看谁能干谁就做,不然这个事件就废弃了。

没人能干的情况下

场景二:“总经理良心发现,接手工作”

总经理是把工作接手了,但是他一定能完成么?,我们分开讨论

2.1 经理(MyViewGroupA)处理好了

此时,我们将MyViewGroupAonTouchEvent返回值置位 true

总经理(MyViewGroupA)处理好了,事件被消费了。

image.png

2.2 经理(MyViewGroupA)没能处理

此时,我们将MyViewGroupAonTouchEvent返回值置位 false

我们可以看到:总经理没能处理掉,则这个事件有上交到的董事长(MainAcitivy)处,要是董事长能处理,则事件就被消费了,不要这个事件就会被废弃掉

场景三:“部长做了好人,接手工作”

情形同上。

六、 总结

经过上面的学习,我相信你对事件传递机制已经有了清楚的认识,是不是很简单呢!
最后还是用一幅图总结吧:

image.png

参考

《Android群英传》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容