Android事件分发机制是Android开发者必须了解的知识,这方面的内容很多,自己纯看文章总觉得比较抽象,自己写了个demo,理一下事件分发的流程,加深印象。
view结构
PhoneWindow 的指示通过 DecorView 传递给下面的 View,下面 View 的信息也通过 DecorView 回传给 PhoneWindow。这里我们主要聊聊ViewGroup与view的事件分发
事件分发dispatchTouchEvent一般改写不多,主要关注另外两个。
事件拦截onInterceptTouchEvent,true,拦截,交给自己的onTouchEvent处理,不传给下级;false,不拦截,传给下级。
事件消费onTouchEvent,true,自己搞定消费,不用上传;false,上传。
事件模拟
如图布局,最外层的父布局ViewGroupA,中间层的ViewGroupB,最里层的ViewC
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.qhyccd.event.ViewGroupA
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="100dp"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@color/colorRed">
<com.qhyccd.event.ViewGroupB
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@color/colorYellow">
<com.qhyccd.event.ViewC
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorBlue" />
</com.qhyccd.event.ViewGroupB>
</com.qhyccd.event.ViewGroupA>
</FrameLayout>
首先模拟下以上场景,A、B、C三个角色,A>B>C
ViewGroupA
public class ViewGroupA extends LinearLayout {
public ViewGroupA(Context context) {
super(context);
}
public ViewGroupA(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupA(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("》》》", " ViewGroupA dispatchTouchEvent ");
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i("》》》", " ViewGroupA onInterceptTouchEvent ");
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("》》》", " ViewGroupA onTouchEvent ");
return super.onTouchEvent(event);
}
}
ViewGroupB
public class ViewGroupB extends LinearLayout {
public ViewGroupB(Context context) {
super(context);
}
public ViewGroupB(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ViewGroupB(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i("》》》", " ViewGroupB dispatchTouchEvent ");
return super.dispatchTouchEvent(ev);;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i("》》》", " ViewGroupB onInterceptTouchEvent ");
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("》》》", " ViewGroupB onTouchEvent ");
return super.onTouchEvent(event);
}
}
ViewC
public class ViewC extends View {
public ViewC(Context context) {
super(context);
}
public ViewC(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ViewC(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.i("》》》", " ViewC dispatchTouchEvent ");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("》》》", " ViewC onTouchEvent ");
return super.onTouchEvent(event);
}
}
情景一
默认情况下,点击C区域
ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent
ViewGroupB onInterceptTouchEvent
ViewC dispatchTouchEvent
ViewC onTouchEvent
ViewGroupB onTouchEvent
ViewGroupA onTouchEvent
可见,事件是从A->B->C,再从C->B->A回传
情景二
A想自己把事件拦截,不给下级处理,A里面onInterceptTouchEvent返回ture拦截事件
ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupA onTouchEvent
情景三
B想自己把事件拦截,不给下级处理,B里面onInterceptTouchEvent返回ture拦截事件。
ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent
ViewGroupB onInterceptTouchEvent
ViewGroupB onTouchEvent
ViewGroupA onTouchEvent
B这里只是对事件拦截不往下传递,还是会往上回传的。
如果想让B自己把事件消费,不往上级传递,B的onTouchEvent返回true
ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent
ViewGroupB onInterceptTouchEvent
ViewGroupB onTouchEvent
情景四
C属于最底层view,对事件没有拦截权限,C自己想把事件消费了,C的onTouchEvent返回true,不再往上级回传
ViewGroupA dispatchTouchEvent
ViewGroupA onInterceptTouchEvent
ViewGroupB dispatchTouchEvent
ViewGroupB onInterceptTouchEvent
ViewC dispatchTouchEvent
ViewC onTouchEvent
以上是静态点击事件处理流程,模拟的事件分发机制,通过log打印可以看到事件的传递流程,这篇文章属于基础篇章,后续我们给view添加滑动,通过处理滑动冲突进一步理解事件的分发机制,敬请期待下一篇。