应用场景:
ViewPager嵌套一个RecyclerView和正常的LinearLayout布局页面,实现左右滑动效果。当左滑RecyclerView页面想要实现左右切换页面的效果,出现滑动冲突的问题。
技术概要:
Android 事件分发图示如下:
解决方案如下:
1、自定义CustomViewPager继承自ViewPager,重写其中的onInterceptTouchEvent()拦截触摸事件方法。
/** * 自定义ViewPager,防止RecyclerView与ViewPager之间的滑动冲突 */ public class CustomViewPager extends ViewPager { public CustomViewPager(@NonNull Context context) { super(context); } public CustomViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } //事件拦截 @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction() & MotionEvent.ACTION_MASK; //当用户按下屏幕的那一瞬间产生该事件 if (action == MotionEvent.ACTION_DOWN) { super.onInterceptTouchEvent(ev); //返回false表示不做拦截,事件将向下分发到子View的dispatchTouchEvent方法 //这里就是CustomRecyclerView中重写的dispatchTouchEvent()方法 return false; } //另外两个事件 手在屏幕上移动和抬起, // 事件将不再向下分发而是调用View本身的onTouchEvent方法 return true; } }
2、自定义CustomRecyclerView继承自RecyclerView,重写其中的dispatchTouchEvent()方法,触摸事件的分发,是从这个方法开始的。
/** * 自定义RecyclerView */ public class CustomRecyclerView extends RecyclerView { private int mLastX; private int mLastY; public CustomRecyclerView(@NonNull Context context) { super(context); } public CustomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public CustomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } //处理触摸事件的分发 是从dispatchTouchEvent开始的 @Override public boolean dispatchTouchEvent(MotionEvent event) { //触摸点相对于其所在组件原点的X坐标 int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //手按下屏幕,父布局没有作用,进行拦截 //让父布局ViewPager禁用拦截功能,从而让父布局忽略事件后的一切行为 //requestDisallowInterceptTouchEvent(true)表示: //getParent() 获取到父视图 父视图不拦截触摸事件 //孩子不希望父视图拦截触摸事件 getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: //水平移动的增量 int deltaX = x - mLastX; int deltaY = y - mLastY; //Math.abs绝对值 if (Math.abs(deltaX) > Math.abs(deltaY)) { //当水平增量大于竖直增量时,表示水平滑动,此时需要父View去处理事件,所以不拦截 //让父布局ViewPager使用拦截功能,从而让父布局完成事件后的一切行为 //requestDisallowInterceptTouchEvent(false)表示: //孩子希望父视图拦截触摸事件,也就是让CustomViewPager拦截触摸事件,进行左右滑动 getParent().requestDisallowInterceptTouchEvent(false); } break; default: break; } mLastX = x; mLastY = y; return super.dispatchTouchEvent(event); } }
这样就可以解决以上我所说的问题,记录,总结一下,方便后期学习与回顾!