前言
上一节讲解了Android事件传递机制的理论知识点,那么这一节就来具体分析项目中的具体场景
Android中事件传递机制 - 理论知识
Android中事件传递机制 - 滑动冲突
1. 关于滑动冲突
在开发中,滑动冲突有很多,比如ScrollView嵌套ListView、ScrollView嵌套ViewPager、ViewPager嵌套ScrollView等等各种嵌套之后的滑动冲突,归根结底可以分为两种:
1>:同方向滑动冲突:
比如ScrollView嵌套ListView;
2>:不同方向滑动冲突:
比如ScrollView嵌套ViewPager、ViewPager嵌套ScrollView;
2. ScrollView嵌套ViewPager冲突
冲突原因:
ScrollView直接拦截事件,没有把事件向下级分发,导致ViewPager没有获取到事件,所以滑动ViewPager没有效果;解决方案1:从最外层 父View考虑
自定义一个MyScrollView继承ScrollView,重写 onInterceptTouchEvent方法,在 Action_Move事件中判断,如果水平滑动距离大于竖直滑动距离,则return false,表示不拦截事件,把事件分发到下一级控件,交由下一级处理;
public class MyScrollView extends ScrollView{
private float xDistance;
private float yDistance;
private float xLast;
private float yLast;
public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyScrollView(Context context) {
super(context);
}
/**
* 在该方法中进行判断
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
xDistance = yDistance = 0.0f;
xLast = ev.getX();
yLast = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
xDistance += Math.abs(curX - xLast);
yDistance += Math.abs(curY - yLast);
if(xDistance > yDistance)
return false;
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
}
- 解决方案2:从最里层 子View考虑
需要在 最里层 子View的 Action_Move事件中判断:
如果水平滑动距离大于竖直滑动距离,表示不让 父控件拦截事件,调用
子View.getParent().requestDisallowInterceptTouchEvent(true);
如果竖直滑动距离大于水平滑动距离,就不要让 子View的ViewPager滑动,就拦截事件, 调用 子View.getParent().requestDisallowInterceptTouchEvent(false);
carouselView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
carouselView.getParent().requestDisallowInterceptTouchEvent(true);
int x = (int) event.getRawX();
int y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int deltaY = y - lastY;
int deltaX = x - lastX;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
carouselView.getParent().requestDisallowInterceptTouchEvent(true);
} else {
carouselView.getParent().requestDisallowInterceptTouchEvent(false);
}
default:
break;
}
return false;
}
});
注意
requestDisallowInterceptTouchEvent表示:如果 子View不希望 父View拦截事件,让自己可以处理事件,可以在 子View的 Action_Move事件中调用这个方法,传递true即可