UFO中文网

 找回密码
 注册会员
查看: 63|回复: 0
收起左侧

安卓事件分发机制小知识

[复制链接]
online_member 发表于 2023-6-9 09:00:39 | 显示全部楼层 |阅读模式
安卓事件分发机制小知识
                    
事件分发机制
Android事件分发机制是指将触摸屏的事件(MotionEvent)传递到某个具体的视图(View)并处理的整个过程。
事件分发的顺序是:Activity -> ViewGroup -> View,即事件先传到Activity,再传到ViewGroup,最终再传到View。
事件分发的过程由三个方法协作完成:dispatchTouchEvent(),onInterceptTouchEvent()和onTouchEvent()。

dispatchTouchEvent():负责将事件分发给子视图或者自己处理。
onInterceptTouchEvent():只有在ViewGroup中才有,用于拦截事件,决定是否传递给子视图。
onTouchEvent():负责处理事件,返回true表示消费了事件,返回false表示不消费事件。
ViewGroup事件分发机制流程
安卓事件分发机制小知识96 / 作者:UFO爱好者 / 帖子ID:117574
View事件分发机制流程
安卓事件分发机制小知识130 / 作者:UFO爱好者 / 帖子ID:117574
Android事件分发流程
安卓事件分发机制小知识264 / 作者:UFO爱好者 / 帖子ID:117574
自定义ViewGroup事件分发
自定义ViewGroup的事件分发,主要是重写onInterceptTouchEvent()方法,来决定是否拦截事件,以及重写onTouchEvent()方法,来处理事件。

onInterceptTouchEvent():返回true表示拦截事件,不再传递给子视图,而是交给自己的onTouchEvent()方法处理。返回false表示不拦截事件,继续传递给子视图的dispatchTouchEvent()方法。
onTouchEvent():返回true表示消费了事件,不再向上传递。返回false表示不消费事件,向上传递给父视图的onTouchEvent()方法。

具体的实现步骤可以参考以下的示例代码:?
public class CustomViewGroup extends ViewGroup {
public CustomViewGroup(Context context) {
super(context);
}
public CustomViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
// 重写onMeasure()方法,测量子视图的大小和自身的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 调用每个子视图的measure()方法,传入相应的测量规格
for (int i = 0; i
// 重写onLayout()方法,摆放子视图的位置
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 根据自己的需求,调用每个子视图的layout()方法,传入相应的位置参数
for (int i = 0; i
// 重写onInterceptTouchEvent()方法,决定是否拦截事件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 根据自己的需求,返回true或false
return true;
}
// 重写onTouchEvent()方法,处理事件
@Override
public boolean onTouchEvent(MotionEvent event) {
// 根据自己的需求,返回true或false
return true;
}
}
如何解决滑动冲突
滑动冲突是指当两个或多个视图(View)具有相同或不同方向的滑动能力时,可能出现的滑动行为不符合预期的情况。
解决滑动冲突的基本思路是:明确哪个视图应该处理哪些滑动事件,然后通过拦截或不拦截事件来实现。
解决滑动冲突的方法有两种:外部拦截法和内部拦截法。

外部拦截法:指在父视图(ViewGroup)的onInterceptTouchEvent()方法中根据滑动方向和条件来判断是否拦截事件,然后交给自己或子视图的onTouchEvent()方法处理。
内部拦截法:指在子视图(View)的onTouchEvent()方法中根据滑动方向和条件来判断是否处理事件,如果不处理则调用父视图(ViewGroup)的requestDisallowInterceptTouchEvent()方法来请求父视图不要拦截事件。

具体的解决方案可以参考以下的示例代码:
// 外部拦截法
public class MyViewPager extends ViewPager {
private int lastX;
private int lastY;
public MyViewPager(Context context) {
super(context);
}
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
intercepted = false;
// 调用ViewPager的onInterceptTouchEvent方法,初始化mActivePointerId
super.onInterceptTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - lastX;
int deltaY = y - lastY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// 横向滑动,拦截事件
intercepted = true;
} else {
// 纵向滑动,不拦截事件
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;
default:
break;
}
lastX = x;
lastY = y;
return intercepted;
}
}
// 内部拦截法
public class MyListView extends ListView {
private int lastX;
private int lastY;
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 父视图不要拦截事件
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - lastX;
int deltaY = y - lastY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// 横向滑动,父视图拦截事件
getParent().requestDisallowInterceptTouchEvent(false);
} else {
// 纵向滑动,父视图不要拦截事件
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
lastX = x;
lastY = y;
return super.dispatchTouchEvent(ev);
}
}
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

UFO中文网

GMT+8, 2024-11-24 17:26

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表