标签:android style blog http color java os io
首先,我们需要 知道什么是ViewGroup,它和普通的View有什么区别?
ViewGroup就是一组View的集合,它包含很多子View和ViewGroup,是Android 所有布局的父类或间接父类.
但ViewGroup也是一个View,只不过比起View,它可以包含子View和定义布局参数的功能.
现在,通过一个Demo演示Android中ViewGroup的事件分发机制.
首先我们来自定义一个布局,命名为MyLayout,继承自LinearLayout,如下 所示:
public class MyLayout extends LinearLayout {
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
然后,打开主布局文件activity_main.xml,在其中加入我们自定义的布局:
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/my_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button1" />
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button2" />
可以看到,我们在MyLayout中添加了两个按钮,接着在MainActivity中为这两个按钮和MyLayout都注册了监听事件:
myLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "myLayout on touch");
return false;
}
});
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "You clicked button1");
}
});
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "You clicked button2");
}
});
我们在MyLayout的onTouch方法,和Button1、Button2的onClick方法中都打印了一句话。现在运行一下项目,效果图如下所示:
分别点击一下Button1、Button2和空白区域,打印结果如下所示:
当你点击按钮时,MyLayout的Touch事件并不会被触发,而在点击除按钮之外的空白部分,却能触发MyLayot的Touch事件.
难道事件是从View传递到ViewGroup中的?现在下结论还太早.
查阅文档,发现ViewGroup中还有一个onInterceptTouchEvent()方法,
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
看Intercept,知道这应该是一个拦截器,拦截Touch事件的.但默认确实对所有的Touch都不拦截.
在MyLayout中重写一下这个方法,然后返回一个true.
public class MyLayout extends LinearLayout {
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
}
现在再次运行项目,然后分别Button1、Button2和空白区域,打印结果如下所示:
你会发现,不管点击在哪里,永远都只会触发MyLayout的Touch事件.按钮的点击事件被完全屏蔽掉了.
所以得出结论:Touch事件会先分发到ViewGroup中,再传递到View中.
上篇有个结论,触摸任何控件,都会调用dispatchTouchEvent()方法.其实不太准确.
实际情况是,当点击了某个控件,首先会调用所在布局ViewGroup的dispatchTouchEvent(),在方法里,找到子View,调用子VIew的dispatchTouchEvent.
当点击了MyLayout时,就会调用MyLayout的dispatchTouchEvent方法,但是MyLayout并没有这个方法,直到父类Linearlayout的父类ViewGroup中才有.
下面是ViewGroup中dispatchTouchEvent()的源码:
在第13行中,对onInterceptTouchEvent取反,因此如果在onInterceptTouchEvent中返回了false,会让表达式成立.
结合之前的例子,在MyLayout重写了onInterceptTouchEvent,返回true,结果导致所有的按钮事件都被屏蔽.所以得出结论,按钮的点击处理事件,都是在13行中内部进行的.
在上篇中,得出结论,调用View的dispatchTouchEvent方法都是有返回值的.如果一个控件是可以点击的,那么dispatchTouchEvent的返回值必定是true.
因此如果按钮的点击事件得到执行,就会将MyLayout的Touch事件拦截掉.
如果不是点击的按钮,而是空白区域,则31行一定不会返回true了,而是执行50行的return super.dispatchTouchEvent(ev); 这句代码会调用View中的dispatchTouchEvent方法.因为ViewGroup的父类就是View.因此MyLayout的Touch方法会得到执行.
看一下整个ViewGroup事件分发过程的流程图:
1. Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。
2. 在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。
3. 子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件。
Android事件分发机制详解(2)----分析ViewGruop的事件分发,布布扣,bubuko.com
Android事件分发机制详解(2)----分析ViewGruop的事件分发
标签:android style blog http color java os io
原文地址:http://www.cnblogs.com/aibuli/p/1092a3fda6e16fac32fd342131dc48b4.html