点击事件的处理包括三个函数:
分别为传递——dispatchTouchEvent()函数、拦截——onInterceptTouchEvent()函数、消费——onTouchEvent()函数
Activity类: | Activity | dispatchTouchEvent(); onTouchEvent(); |
View容器(ViewGroup的子类): | FrameLayout、LinearLayout…… ListView、ScrollVIew…… | dispatchTouchEvent(); onInterceptTouchEvent(); onTouchEvent(); |
View控件(非ViewGroup子类): | Button、TextView、EditText…… | dispatchTouchEvent(); onTouchEvent(); |
dispatchTouchEvent() | 用来分派事件。 其中调用了onInterceptTouchEvent()和onTouchEvent(),一般不重写该方法 |
onInterceptTouchEvent() | 用来拦截事件。 ViewGroup类中的源码实现就是{return false;}表示不拦截该事件, 事件将向下传递(传递给其子View); 若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递, 事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法 |
onTouchEvent() | 用来处理事件。 返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View); 返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理 |
传递流程
(1) 事件从 Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的 View(ViewGroup)开始一直往下(子 View)传递。子 View 可以通过 onTouchEvent()对事件进行处理。
(2) 事件由父 View(ViewGroup)传递给子 View,ViewGroup 可以通过 onInterceptTouchEvent()对事件做拦截,停止其往下传递。
(3) 如果事件从上往下传递过程中一直没有被停止,且最底层子 View 没有消费事件,事件会反向往上传递,这时父 View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到 Activity 的 onTouchEvent()函数。
(4) 如果 View 没有对 ACTION_DOWN 进行消费,之后的其他事件不会传递过来。
(5) OnTouchListener 优先于 onTouchEvent()对事件进行消费。
上面的消费即表示相应函数返回值为 true。
即Touch事件的传递是由最顶层的ViewGroup -》 View的,Touch的处理是由最内层的View向顶层传递的
通过实例来解析
第一种情况,LinearLayout的onInterceptTouchEvent方法返回false,onTouchEvent返回true,Button的onTouchEvent也返回true
public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
System.out.println("MyLInearLaout: actiondown");
}
return true;
}
}
public class MyButton extends Button {
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("MYbutton pressed");
break;
default:
break;
}
return true;<pre name="code" class="java"><span style="white-space:pre"> </span>}
}
这种情况下,事件的传递是由MyLinearLayout传递给MyButton的(即传递是由视图树的顶层向下传递的),由于MyLinearLayout没有重新onInterceptTouchEvent方法,所以Touch事件并别有被拦截,所以Touch事件由MyButton来处理,MyButton的onTouchEvent方法返回为true表示该事件被它消费掉了,不会在向上传递了(向上指的是视图树),所以MyLinearLayout的onTouchEvent方法就不会被执行了
第二种情况就是MyButton的onTouchEvent方法返回false
<span style="color:#333333;">public class MyButton extends Button {
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("MYbutton pressed");
break;
default:
break;
}
return </span><span style="color:#ff6666;">false</span><span style="color:#333333;">;
}
}</span>
Touch事件由上向下传递到了MyButton,由于MyButton已经是树的最下端了,所以就会执行MyButton的onTouchEvent方法,虽然这里该方法被执行了, 但是onTouchEvent返回false,所以该Touch事件没有被消费掉 ,那么Touch事件就会调转向上传递,传递到了MyLinearLayout,就会执行它的onTouchEvent方法,该方法返回true,所以该Touch事件就被消费掉了,不会再向上传递了 第三种情况:MyLinearLayout重写了onInterceptTouchEvent方法,并返回true,对Touch事件进行了拦截
<span style="font-size:18px;">public class MyLinearLayout extends LinearLayout {
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
System.out.println("MyLInearLaout: actiondown");
}
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return <span style="color:#ff0000;">true</span>;
}
}</span>
Touch事件传递到MyLinearLayout时,由于onInterceptTouchEvent方法返回true,所以该事件就被拦截了,不会在向下传递了,MyLinearLayout就相当于到了树的最下端,那么就会执行它的onTouchEvent方法,而它的onTouchEvent方法返回true,所以该Touch事件就被消费掉了
参考:
http://blog.csdn.net/morgan_xww/article/details/9372285
http://a.codekk.com/detail/Android/Trinea/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20View%20%E4%BA%8B%E4%BB%B6%E4%BC%A0%E9%80%92
http://blog.csdn.net/cyp331203/article/details/45071069
<pre name="code" class="java">