标签:
欢迎转载,转载请注明原文出处http://blog.csdn.net/lavor_zl/article/details/51198634,谢谢。
事件分发机制的学习主要来自下面两篇博文:
这两篇博文写的非常好,但是看完了这两篇博文还是有一些不理解的地方,缺少一丝明悟。于是亲自写下几种情况的代码,来看事件分发的结果,从而验证事件分发机制。验证完后瞬间有了一种明悟,感觉豁然开朗。纸上学来终觉浅,绝知此事要躬行。
我的程序是在MainActivity中有一个自定义的MyLayout布局,MyLayout布局下面有一个自定义的MyButton。
PS:表格中super代表返回父类中同名的方法,–代表没有此方法,无返回值代表该方法的返回类型是void。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
通过这两个结果我们可以发现事件是从上往下分发的Activity->ViewGroup->View。
但是这两个结果还有一个不对应的地方,那就是第一个结果的MyLayout的onInterceptTouchEvent方法在抬起时没有执行,而第二个结果执行了。这是因为ViewGroup中的dispatchTouchEvent方法只会在按下时或者该事件会继续往下分发时才会调用onInterceptTouchEvent方法。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
情况2的输出结果明显比情况1少,这是因为MyLayout中onInterceptTouchEvent方法和onTouchEvent方法都是在ViewGroup中的dispatchTouchEvent方法中调用的,而情况二下面MyLayout中dispatchTouchEvent方法的返回值是false,不是super.dispatchTouchEvent(ev),没有调用ViewGroup中的dispatchTouchEvent方法。因为返回值是false,所以会将事件返回给上级的onTouchEvent方法进行消费而不会继续往下分发,因此MyLayout中的onTouch方法和onClick方法也不会执行。这样就导致情况2下面点击非MyButton区域与点击MyButton区域的结果相同了。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
情况3的输出结果明显比情况2还少一条,这是因为情况3中MyLayout中dispatchTouchEvent方法的返回值是true,事件将由MyLayout中dispatchTouchEvent方法消费,不会向上传递由上级的onTouchEvent方法进行消费,所以情况3的输出结果比情况2还少1条。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
情况4的输出结果与情况1完全一样,这是因为MyLayout中的onInterceptTouchEvent方法中的返回值一个是false,一个是super.dispatchTouchEvent(event),而ViewGroup的dispatchTouchEvent方法中什么都没有,就是返回值是false。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
情况5点击非MyButton区域和点击MyButton区域的结果相同,这是因为MyLayout中的onInterceptTouchEvent方法的返回值是true,表示将事件进行拦截,并将事件交给当前View的onTouchEvent进行处理,事件不会继续往下分发了。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
情况6中点击点击非MyButton区域与情况1中点击点击非MyButton区域结果不同,这是因为情况6中的MyLayout中onTouchEvent方法返回值是false,表示当前View解决不了,会把事件向上传递交给上级的onTouchEvent方法处理。我们发现在抬起事件时,MainActivity没有将事件分发给MyLayout,这是因为在之前的按下事件时,MainActivity将事件分发给MyLayout,而MyLayout之前没有将事件处理成功,所以在抬起事件时,MainActivity不会将事件分发给MyLayout。但是在下次抬起事件时,MainActivity还是会将将事件分发给MyLayout,这是因为记忆MyLayout之前没有将事件处理成功元素在每次抬起事件时,会通过父级的dispatchTouchEvent方法清空。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
情况7中点击点击非MyButton区域比情况1中点击点击非MyButton区域的结果少1条,这是因为MyLayout中的onTouchEvent方法的返回值是true,表示当前View会接受并消费该事件,但是此时并没有调用View中的onTouchEvent方法,不调用该方法Click事件就无法被响应。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
情况8中点击点击非MyButton区域比情况1中点击点击非MyButton区域的结果少,这是因为MyLayout中的onTouch方法返回值是true,若某个View的的onTouch方法返回值是true,则结束,若返回值是false则调用该View的onTouchEvent方法。
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
点击非MyButton区域,结果如下:
点击MyButton区域,结果如下:
该实例验证刚好验证了Android 编程下 Touch 事件的分发和消费机制里面的Touch 事件分析。
下面将该博文的Touch 事件分析部分引用出来:
事件分发:public boolean dispatchTouchEvent(MotionEvent ev)
Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:
事件拦截:public boolean onInterceptTouchEvent(MotionEvent ev)
在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动的分发给当前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件拦截逻辑如下:
事件响应:public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情况下 onTouchEvent 会被调用。onTouchEvent 的事件响应逻辑如下:
情况6,7,8还有一些总结之外的知识点,要注意。
标签:
原文地址:http://blog.csdn.net/lavor_zl/article/details/51198634