2019-01-16 android之View和ViewGroup事件分发机制分析(一)(View的事件分发机制)

转自    https://blog.csdn.net/gsw333/article/details/51995391

一个View和ViewGroup都有自己的事件分发机制,都是写好了的,可能有些人就问了,既然都写好了,那还需要学习什么?直接用不就行了。没错,我给你做了一碗可以吃的便便,然后你不用自己做了,直接吃,但是你又嫌弃便便味道不好吃,那你咋搞?当然自己做了!那不就行了,存在即合理~鸡汁~如果能认真看完我这篇文章,相信肯定能对View的事件分发机制很了解了。

事件分发机制根据View和ViewGroup的不同所处理的方式也不同:

a.dispatchTouchEvent() :用来进行事件的分发,它的返回结果表示是否消耗掉当前的事件,但是它的返回结果也是受下面两个方法的影响

b.onInterceptTouchEvent():用来表示是否拦截当前事件,即是否将事件传递给下一层

c.onTouchEvent():这个方法应该都很熟悉了,对事件的处理,比如手指按下,移动,抬起,对这些动作的处理

ViewGroup是a.b.c三个方法都有,而View只有a.c 两个方法,至于原因显而易见了吧。

首先,我们先来看View的事件分发机制,我们自定义View继承ImageView(代码片段1):


我们现在看看打印结果:


从结果我们可以看出来一件事:那就是View的事件的这两个方法是先执行dispatchTouchEvent方法再执行onTouchEvent 方法的,dispatchTouchEvent是用来分发事件用的,执行它,此时,如果它直接返回false,那么它就不消费事件,那么它就不会执行onTouchEvent方法了,因为已经返回false表示它不需要消费touch事件,我们将dispatchTouchEvent方法改为如下进行测试(代码片段2):


打印结果就是:


我再说下,dispatchTouchEvent方法的返回值表示是否消费当前事件,它是用来事件分发的,相信看上面代码能看出来了,执行了dispatchTouchEvent里面对ACTION_DOWN直接返回false代表不消费不进行事件的分发,所以就不会继续super.dispatchTouchEvent()了,更别说onTouchEvent方法了,不会进行任何下一步了。如果我们没有直接返回false而是直接break,那么就没有提前结束这个方法,因为你直接retrun后方法就直接结束了,所以没有return的时候,下面就super.dispatchTouchEvent,这个里面做了些什么呢?说实话,我也没怎么看源码,毕竟我也是渣渣,它里面你可以这么认为,它里面做的操作就是:受到onTouchEvent方法的影响,什么意思呢?咋们不是没有直接return吗?所以此时dispatchTouchEvent方法还没有进行值的返回,那没有return时的返回值就是onTouchEvent的返回值了,如果onTouchEvent返回true就是代表当前View消费touch事件了,false就是代表不消费。一句话总结就是:dispatchTouchEvent方法表示是否消费事件,如果dispatchTouchEvent直接返回false那么就是不消费,我都不消费了还需要分发事件么?不需要,所以结束;如果没有返回那就代表需要进行事件分发,只是分发!分发给当前View予touch事件,但是消不消费就是根据onTouchEvent来决定了,它返回true就代表消费,那么dispatchTouchEvent就返回true。但是,细心的人会问了,我的onTouchEvent中ACTION_MOVE和ACTION_UP没有返回false,那为啥没打印执行呢?因为我们知道我们进行touch事件的时候,手指是先按下、移动、抬起的,所以touch事件的顺序是ACTION_DOWN, ACTION_MOVE, ACTION_UP。所以onTouchEvent方法里面第一个进行判断是事件是ACTION_DOWN,里面的判断是执行log打印,然后return false了,ACTION_DOWN的打印出来了再进行return的。那有人问了,ACTION_MOVE和ACTION_UP也是先log再return的啊,为啥它们就不打印Log了?因为View的事件处理中,如果第一个动作ACTION_DOWN不消费,那么其他的后续动作事件ACTION_MOVE之类的都不会再传过来给它了,所以才会没有后续的执行打印。

上面已经详细说明了dispatchTouchEvent和onTouchEvent方法之间的关系了,下面用一段代码来试试(代码片段3):


注意看上面的代码,我们让dispatchTouchEvent方法无论什么动作ACTION_DOWN还是ACTION_MOVE等等,全都返回false,那么按照我上面说的,返回false表示不消费事件,所以onTouchEvent应该是不执行的,那么我们看看打印结果对不对:

返回结果是只有一个dispatchTouchEvent  DOWN,没有执行onTouchEvent任何动作,所以印证上面我说的对了。而且也只打印了DOWN事件,也说明了我上面说的:如果不消费DOWN事件,那么后续的都不会给它了。

注意:如果我们将所有方法都用默认的,不自己return false,即(代码片段1)一样,打印结果上面已经试过,是:


我们示例是继承的ImageView,如果我们改为TextView你就会发现打印结果是:

这是为什么呢?因为View的onTouchEvent默认会消费事件(前提是它的clickable和longclickable不同时为false),所有View的longClickable都是默认false,但是clickable就不一定了,ImageView的clickable默认是true,而TextView的clickable默认是false,即TextView的clickable和longclickable同时为false了,那么它默认不会消费事件了,所以它的onTouchEvent中的DOWN动作是返回false的,默认不消费,所以才没有后续的UP事件。

好了,上面对View中的两个方法的说明已经很详细了,相信看完后能理解我所说的了,那么下面我们接下来分析一下View的onTouch方法和onTouchEvent方法的关系,onTouch方法就是setOnTouchListener里面所重写的onTouch方法,我们来重写并默认执行看看(代码片段4):


上面是onTouch方法,下面是TouchView里面的dispatchTouchEvent方法和onTouchEvent方法(代码片段5)


我们获取布局中用的我们上面写的TouchView,然后给它setOnTouchListener,然后现在打印结果:

看打印结果,先执行的是dispatchTouchEvent 方法,这个不用解释了,因为它是进行事件分发的,无论是onTouch还是onTouchEvent都需要先被分发事件才能处理事件,所以先执行dispatchTouchEvent 可以理解。然后发现onTouchEvent方法居然比onTouch方法后执行,因为确实是这样的,可以看源代码,先执行onTouch再执行onTouchEvent方法的,因为源码中onTouchEvent方法执行的前提是对onTouch方法的返回值做判断,如果返回值是false,那么就会进入onTouchEvent方法中;如果返回值是true,那么就不会进入,因为会认为事件被onTouch方法消费了,所以不再执行了,结论就是:onTouch方法的优先级高于onTouchEvent方法。如果想看源码分析的,就去看看郭神和洪洋大神的吧,他们博客做了详细的源码分析,我就不写了,毕竟我不是郭神他们啊~菜鸟路过~

上面已经说了onTouch方法优先于onTouchEvent方法,做了两个方法的联系分析,下面再来分析一下onclick事件,有人会问了,onclick事件和touch事件难道还有关系?其实想一想就知道,肯定有关系了,因为你onclick不就是触摸按钮么,点击一下就是一个ACTION_DOWN和ACTION_UP事件。对于onclick事件,它们的优先级关系是:

onTouch > onTouchEvent >onclick事件,为什么呢?因为onclick事件的执行就是在onTouchEvent里面的,下面我们看看代码(代码片段6):


设置下onClick事件,然后打印结果:


发现调用顺序是dispatchTouchEvent - onTouch - onTouchEvent - onclick,那么我上面说的onclick事件的执行就是在onTouchEvent方法里面就能说得过去了,其实源码里面onclick事件的处理是在onTouchEvent方法中的ACTION_UP的处理当中的,所以才说onclick事件在onTouchEvent中进行的。不要以为完事了,记得上面我说过的话吧:

View的onTouchEvent默认会消费事件(前提是它的clickable和longclickable不同时为false),所有View的longClickable都是默认false,但是clickable就不一定了,ImageView的clickable默认是true,而TextView的clickable默认是false,即TextView的clickable和longclickable同时为false了,那么TextView它默认不会消费事件了,所以它的onTouchEvent中的DOWN动作是返回false的,默认不消费,所以才没有后续的UP事件。

那么按照我说的,(记住我说的两个点:1.TextView的onTouchEvent方法默认返回false不消费事件;2.onClick事件的处理是在onTouchEvent方法里面的ACTION_UP动作处理里面的。那么按照我说的,如果ACTION_UP动作不执行,onclick事件就不会触发了?),现在我们将(代码片段1)继承ImageView改为继承TextView,然后再设置onclick事件即setOnClickListener:



然后打印结果:


我们看看结果,

第一个问题:TextView的onTouchEvent方法默认返回false不消费的,但是为啥DOWN和UP动作都执行了,返回的true呢?

第二个问题:为什么执行了onclick方法,TextView的onTouchEvent方法默认返回false,那么UP就不会执行,为啥还有onclick?

这两个问题的原因都是一个:因为我们设置了onclick事件即setOnclickListener,它会让当前View的clickable变为true,所以那么View的onTouchEvent方法就会默认返回true了(不懂的自己回忆我前面说过的:View的onTouchEvent默认会消费事件(前提是它的clickable和longclickable不同时为false)),所以现在一切都能解释通了。

关于View的事件分发机制就先说到这里了,差不多都说完了,应该很清晰了,如果看完了这篇文章,相信View的事件分发机制就明白了,至于要看源码解析的就去看郭神和洪洋大神的博客吧,我就懒得重复他们的了。ViewGroup的事件分发机制和View的不一样我说过的,多一个onInterceptTouchEvent方法,关于ViewGroup的事件分发机制的分析我会在后面的文章进行说明。

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

推荐阅读更多精彩内容