转载本专栏每一篇博客请注明转载出处地址,尊重原创。此博客转载链接地址:点击打开链接 http://blog.csdn.net/qq_32059827/article/details/52577017
如果想参与实际开发项目,若不理解事件分发回传机制的话,几乎等于“”摸黑抓鳅”,因为几乎每个项目都会出现滑动冲突问题;而要想解决滑动冲突问题,必须先了解甚至掌握事件分发传递机制。等到了解决滑动冲突时,至少没有一种“断层”的感觉。所以本专栏开篇先介绍事件机制,对安卓中的事件机制,做一个详细的介绍与分析。
首先,View的几个基本的继承关系:
本博客案例的图层:
新建三个类(分别按照上边图解的方式,写出这几个有关事件的方法)。
这个很简单,就不罗列了。例如类似容器1的代码:
public class ViewGroupOne extends LinearLayout { public ViewGroupOne(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public ViewGroupOne(Context context) { super(context); // TODO Auto-generated constructor stub } /** * 分发事件 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+分发+dispatchTouchEvent"); return super.dispatchTouchEvent(event); } /** * 拦截事件 */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+拦截+onInterceptTouchEvent"); return super.onInterceptTouchEvent(event); } /** * 处理事件 */ @Override public boolean onTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+处理+onTouchEvent"); return true; } }笔者是吧事件抽取成工具类了,当然,每个方法里都写都写一遍事件情况也无所谓,只不过重复了一些代码罢了。
接着写一个复合上边图解的布局:
<com.example.event.ViewGroupOne xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ff0000" android:orientation="vertical" > <com.example.event.ViewGroupTwo android:layout_width="200dp" android:layout_height="200dp" android:background="#00ff00" > <com.example.event.MyTextView android:layout_width="100dp" android:layout_height="100dp" android:background="#0000ff" > </com.example.event.MyTextView> </com.example.event.ViewGroupTwo> </com.example.event.ViewGroupOne>注意:记得写类的全称。
好了,废话不多说,直接运行程序说话。通多点击手机屏幕。对所有的可能情况全部罗列如下:
事件1:点击红色位置。看log输出
可以看到,整个事件是Activity先得到事件,调用它的dispatchTouchEvent分发事件,传递给ViewGroupOne,调用ViewGroupOne的dispatchTouchEvent方法,此时这个返回值默认return super.dispatchTouchEvent(event);把事件传递给自己的onInterceptTouchEvent(MotionEvent event)拦截事件,它的返回值也是默return super.onInterceptTouchEvent(event);认,即没做拦截;自己的onTouchEvent(MotionEvent event)处理方法被调用,默认不处理,return super.onTouchEvent(event);。这样事件没有被消费,又返回给Activity的onTouchEvent(MotionEvent event) ,Activity也是默认返回值。事件销毁。由up事件log日志,也可以看到:最后松手时,已经与ViewGroupOne没有任何关系。
事件2:点击绿色区域l。看log输出:
这里就会显而易见了。多了ViewGroupTwo,就多往下传递一层,最里面这层每做处理,最后还是回传回来。到activity事件全部消失
事件3:点击蓝色区域:
这个肯定在意料之中,不用解释也很清楚为何打印此log了。
处理1:蓝色区域,MyTextView修改如下代码:
@Override public boolean onTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "MyTextView+处理+onTouchEvent"); return true;//事件消费,不回传 }此时要重新运行程序了再点击蓝色区域,看log:
MyTextView的onTouchEvent(MotionEvent event)返回true的意思是,事件由我来处理。它处理了事件,就不可能出现回传了,出现这种log也是顺理成章了。再看UP事件与分发拦截是一致的。最后在MyTextView中消失。这个时候可以对比一了,一都是默认,可以称之为狭义的回传机制,而二的处理1:我们可以称之为狭义的拦截机制,每一次的往下分发,有可称为狭义的传递机制(称之为狭义,可能逼格略高些,是因为不能代表全部,却也不失一般性;最起码拦截与回传分发大致是什么很清楚了)。那接着就细致开来,从狭义走到广义。
处理2:蓝色区域,MyTextView修改如下代码:
@Override public boolean onTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "MyTextView+处理+onTouchEvent"); return false;//和默认效果一样,回传机制 }再运行,打印看log: 和默认效果是一样的。回看默认解析。
TextView(没有子组件类型)
onTouchEvent()
return true; //事件消费不回传,自己消费掉事件
return false;或者 return super.onTouchEvent() ;//事件回传给父组件
处理3:ViewGroupOne的dispatchTouchEvent方法做如下修改:
@Override public boolean dispatchTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+分发+dispatchTouchEvent"); return true; }运行程序,点击蓝色位置看log:
其实你会发现。不管点击屏幕哪个位置,都打印这样的log
这是因为,ViewGroupOne的dispatchTouchEvent返回true了,相当于在ViewGroupOne的分发事件地方就拦截了事件(称之为拦截,也因为没有回传,从UP日志里也可以看出没有回传)。事件消失。
处理4:ViewGroupOne的dispatchTouchEvent方法做如下修改:
@Override public boolean dispatchTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+分发+dispatchTouchEvent"); return false; }
返回false,表示自己的dispatchTouchEvent不做处理,即不做分发。就回传,回传给activity的onTouchEvent处理,最后事件消失
注意:ViewGroupOne的dispatchTouchEvent方法默认返回super.dispatchTouchEvent(event);的时候是要传递给自己的onTouchEvent方法的,问这个方式是否做拦截。上边其实已经不知不觉介绍了这个情况。此时可以总结,只有在ViewGroupOne的dispatchTouchEvent方法默认返回super.dispatchTouchEvent(event);的时候才会去调用自己的onInterceptTouchEvent(MotionEvent event) 拦截事件,是否拦截。其他都是回传
处理5:ViewGroupOne的onInterceptTouchEvent方法做如下修改:
@Override public boolean onInterceptTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+拦截+onInterceptTouchEvent"); return true; }log情况
自己的onInterceptTouchEvent(MotionEvent event)拦截事件返回为true,表名自己要拦截,不向下传递。调用自己的onTouchEvent(MotionEvent event)是否处理。由于默认不处理,又回传到activity事件消失。
处理6:ViewGroupOne的onInterceptTouchEvent(MotionEvent event)拦截事件返回false
@Override public boolean onInterceptTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+拦截+onInterceptTouchEvent"); return false; }
处理7:ViewGroupOne的onTouchEvent做如下处理:
注意:这个方法想要执行,前提是在ViewGroupOne的onInterceptTouchEvent方法返回true的时候
@Override public boolean onTouchEvent(MotionEvent event) { ActionUtiles.processEvent(event, "ViewGroupOne+处理+onTouchEvent"); return super.onTouchEvent(event); }
返回true,自己处理事件,也就没了回传机制。事件消失
处理8:ViewGroupOne的onTouchEvent返回为false。不用打印也可以清楚,与默认效果是一样的。
2,ViewGroup
dispatchTouchEvent
return true;//自己消费,不往下(子组件)往上传递(不回传)
return false;//自己不处理,回传给父组件onTouchEvent方法处理
return super.dis.....;//问自己onInterceptTouchEvent是否拦截
问自己 >onInterceptTouchEvent
true: 自己消费,调用自己onTouchEvent();不往下传递
false 或 super: 默认往下传递
>onTouchEvent()
true: 自己消费(不回传)
false 或 super: 继续回传
对于ViewGroupTwo和One是一摸一样的。就不再多赘述。最后,再用一张草图做一个收尾::
此草图花费接近一小时时间。。。虽然潦草,但是最能说明问题,包含了所有可能的情况。。
对于拦截机制详细介绍就完毕了,但是除了上边这些情况外,还有许许多多的分支情况;但是大同小异,仔细分析一下,就能得出正确的结论。以后此专栏可能还会再次探讨类似问题。若有问题或建议请留言更正、补充。
笔者花费几个小时,您或许只需要10分钟。欢迎点赞或关注本专栏,Android进阶知识不定期会更新哦。也可关注Android简易实战教程专栏,花5分钟“欣赏”有趣的小案例。
关注本博客,地址:点击打开链接 http://blog.csdn.net/qq_32059827