目录
这篇文章以前写的,后来博客清空重新开始了。最近看到,因此摘抄于此,以便查阅。
在开始分析之前,大家可以先记几个结论,这样便于理解。
结论1:事件一定是先到达父控件上。
结论2:事件简单来说可以分为三种:Down事件、Move事件、Up事件。
PS:
(1) 为了让读者看得更清晰,在代码中只打印了Down事件来分析,其他事件过滤,这样看起来简洁很多。
(2) ViewGroup中才有事件的拦截,View中是没有的。
第一部分:代码片段
本不想附上代码,但如果没有,会让人理解有误,因此还是附上,仅供参考:
1、MainActivity.java
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "--MainActivity--------dispatchTouchEvent-------");
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "--MainActivity--------onTouchEvent-------");
}
return super.onTouchEvent(event);
}
2、ParentsView.java
public class ParentsView extends RelativeLayout {
private String TAG = "touch";
public ParentsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public ParentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public ParentsView(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "--ParentsView--------dispatchTouchEvent-------");
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// TODO Auto-generated method stub
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "--ParentsView--------onInterceptTouchEvent-------");
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "--ParentsView--------onTouchEvent-------");
}
return super.onTouchEvent(event);
}
}
3、SubView.java
public class SubView extends Button {
private String TAG = "touch";
public SubView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public SubView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public SubView(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "--SubView--------dispatchTouchEvent-------");
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "--SubView--------onTouchEvent-------");
}
return super.onTouchEvent(event);
}
}
4、layout.xml
<RelativeLayout 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" >
<com.la.view.ParentsView
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_centerInParent="true"
android:background="@android:color/darker_gray" >
<com.la.view.SubView
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_centerInParent="true"
android:background="@android:color/holo_blue_light"
android:gravity="center"
android:text="@string/hello_world" />
</com.la.view.ParentsView>
</RelativeLayout>
上面代码中ParentsView和SubView分别继承RelativeLayout(间接继承ViewGroup)和Button(间接继承View),这个是为了简单点写,当然我们也可以直接继承ViewGroup或View的。
第二部分:触摸分发、拦截分析
情景一:ParentsView中不分发,也不处理时
就是在ParentsView的dispatchTouchEvent(MotionEvent ev)中返回 true。
就像[经理]直接把[老板]的话当屁放了。
touch : --MainActivity--------dispatchTouchEvent------//老板 分发
touch : --ParentsView--------dispatchTouchEvent-------//经理 不分发,也不处理了,直接抛弃事件
情景二:ParentsView中进行拦截,但不处理事件时
就是在ParentsView中的onInterceptTouchEvent(MotionEvent ev)返回true,但在onTouchEvent(MotionEvent event)中不处理事件,直接上报。
就像[经理]跟[老板]说[不处理!],不往下分配了,而是直接给[老板]自己处理。
touch : --MainActivity--------dispatchTouchEvent------//老板 分发
touch : --ParentsView--------dispatchTouchEvent-------//经理 分发
touch : --ParentsView--------onInterceptTouchEvent----//经理 拦截
touch : --ParentsView--------onTouchEvent-------------//经理 不处理(任务太简单了,不想处理,老板您自己处理吧)
touch : --MainActivity--------onTouchEvent------------//老板 处理或不处理
情景三:ParentsView中进行拦截,但处理事件时
ParentsView中的 onInterceptTouchEvent(MotionEvent ev) 和 onTouchEvent(MotionEvent event)返回true,也就是拦截并处理了。
就像[经理]这次认怂了(老板的话还是要听听的),自己接下任务(很简单)自己处理了。
touch : --MainActivity--------dispatchTouchEvent------//老板 分发
touch : --ParentsView--------dispatchTouchEvent-------//经理 分发
touch : --ParentsView--------onInterceptTouchEvent----//经理 拦截
touch : --ParentsView--------onTouchEvent-------------//经理 自己处理掉
情景四:在SubView中不分发时
也就是在SubView中的dispatchTouchEvent(MotionEvent event)进行返回true。
[老板]和[经理]分配任务了,但是这任务可做可不做,[程序员]直接不安排时间(不分发).
touch : --MainActivity--------dispatchTouchEvent------//老板 分发
touch : --ParentsView--------dispatchTouchEvent-------//经理 分发
touch : --ParentsView--------onInterceptTouchEvent----//经理 不拦截 让部下处理
touch : --SubView--------dispatchTouchEvent-----------//程序员 不分发 觉得没必要处理
情景五:在SubView中分发,但不处理时
就是在ParentsView和SubView都不拦截,也不处理,因此最后任务又回到MainActivity
就像[老板]给[经理]下达新任务,[经理]直接向下分发,[程序员]觉得”没必要处理“,任务就抛给[经理],[经理]把任务又抛给[老板],如果上面还有[大BOSS],那继续上报。
touch : --MainActivity--------dispatchTouchEvent------//老板 分发 touch : --ParentsView--------dispatchTouchEvent-------//经理 分发 touch : --ParentsView--------onInterceptTouchEvent----//经理 不拦截 touch : --SubView--------dispatchTouchEvent-----------//程序员 分发 touch : --SubView--------onTouchEvent-----------------//程序员 不处理 touch : --ParentsView--------onTouchEvent-------------//经理 不处理 touch : --MainActivity--------onTouchEvent------------//老板 处理或不处理,如果上面还有大BOSS,继续上报
情景六:在SubView中分发,但处理时
就是在SubView中的onTouchEvent(MotionEvent event)返回true,进行处理了。
就像[老板]和[经理]的任务来了,这次任务重大,[程序员]必须处理。
touch : --MainActivity--------dispatchTouchEvent------//老板 分发
touch : --ParentsView--------dispatchTouchEvent-------//经理 分发
touch : --ParentsView--------onInterceptTouchEvent----//经理 不拦截
touch : --SubView--------dispatchTouchEvent-----------//程序员 分发(安排日期处理)
touch : --SubView--------onTouchEvent-----------------//程序员 处理并消耗
小结一下
从上面实验得知:
(1)事件一定是从先到父控件(老板、经理)上,然后分发到子控件(程序员)上。
(2)如果控件(比如经理)拦截了事件,就不会再分发给子控件(程序员)上了。
(3)如果控件(比如经理)拦截了事件,且不处理,那么事件会上报给父控件(老板),但不会给子控件(程序员)。
(4)如果控件(比如经理)拦截了事件,也处理了此事件,那么事件就被消耗了,不会上报给父控件(老板),也不会传递给子控件(程序员)。