Android事件分发机制是Android开发者必须了解的知识,这方面的内容很多,自己纯看文章总觉得比较抽象,自己写了个demo,理一下事件分发的流程,加深印象。
view结构
PhoneWindow 的指示通过 DecorView 传递给下面的 View,下面 View 的信息也通过 DecorView 回传给 PhoneWindow。这里我们主要聊聊ViewGroup与view的事件分发
类型 | 相关方法 | ViewGroup | View |
---|---|---|---|
事件分发 | dispatchTouchEvent | √ | √ |
事件拦截 | onInterceptTouchEvent | √ | × |
事件消费 | onTouchEvent | √ | √ |
事件分发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添加滑动,通过处理滑动冲突进一步理解事件的分发机制,敬请期待下一篇。
END
祝大家五一劳动节快乐!致敬奋斗在一线的码农!
欢迎关注微信号