有些需求要在一个页面里面加好多东西,因而会出现嵌套RecyclerView,ViewPager的状况。
可是在嵌套以后,即便使用NestedScrollView也会出现一些问题,好比嵌套RecyclerView会出现滑动卡顿,嵌套ViewPager会出如今ViewPager区域没法上下滑动的问题。
1.先来讲一下嵌套ViewPager没法上下滑动的问题
个人思路是能够在dispatchTouchEvent方法里面,在ACTION_DOWN的时候,记录下y坐标;而后在ACTION_MOVE的时候,经过y坐标的差值,来决定是本身处理,仍是交给父控件ide
public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: downY = ev.getY(); break; case MotionEvent.ACTION_MOVE: if (Math.abs(ev.getY() - downY) > 50) { getParent().requestDisallowInterceptTouchEvent(false); return false; } break; }
这样经过事件分发,把事件拦截交给父控件,能够解决没法上下滑动的问题。
2.再来讲说嵌套RecyclerView出现滑动卡顿的问题
我按照处理ViewPager的方法,想去解决RecyclerView的问题,结果发现这样不行,会产生好多问题。
而后查资料发现一个很简单的方法,覆写LinearLayoutManager的canScrollVertically方法,return false禁止竖直方向的滑动,试了一下果真能够,滑的很顺畅。
既然问题解决了,那么为何一样的方法,能够解决ViewPager的问题,对RecyclerView却不行呢?
既然canScrollVertically方法能够解决,那么我想能够从源码中找canScrollVerticall方法的相关,就能够找出来答案了。就去看了一下源码,果真找到了答案。
源码那么多,怎么找呢?我想既然是触摸滑动的问题,那么应该逃不出分发(dispatchTouchEvent)、拦截(onInterceptTouchEvent)、处理(onTouchEvent)的那三个关于触摸的方法,就在RecyclerView里面搜索canScrollVertically,定位到dispatchTouchEvent方法里面,果真看到了spa
@Override public boolean onInterceptTouchEvent(MotionEvent e) { ...无关代码省略... switch (action) { case MotionEvent.ACTION_DOWN: ...无关代码省略... int nestedScrollAxis = ViewCompat.SCROLL_AXIS_NONE; if (canScrollHorizontally) { nestedScrollAxis |= ViewCompat.SCROLL_AXIS_HORIZONTAL; } if (canScrollVertically) { nestedScrollAxis |= ViewCompat.SCROLL_AXIS_VERTICAL; } startNestedScroll(nestedScrollAxis, TYPE_TOUCH); break; ...... case MotionEvent.ACTION_MOVE: { ...无关代码省略... if (mScrollState != SCROLL_STATE_DRAGGING) { ...无关代码省略... } } break; ...无关代码省略... } return mScrollState == SCROLL_STATE_DRAGGING; }
原来在RecyclerView中,对滑动事件的方法,是在ACTION_DOWN中进行的。
那么若是自定义RecyclerView的话,只要在ACTION_DOWN中进行处理就应该能够了。code
/** * @author zhangyi * @date 2018/9/21 * 解决嵌套RecycleView出现滑动卡顿的问题 */ public class NestedRecycleView extends RecyclerView { public NestedRecycleView(Context context) { super(context); } public NestedRecycleView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public NestedRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { if (e.getAction()== MotionEvent.ACTION_DOWN) { return false; } return super.onInterceptTouchEvent(e); } @Override public boolean onTouchEvent(MotionEvent e) { if (e.getAction()== MotionEvent.ACTION_DOWN) { //这个得加上,表明本身处理点击事件,否则点击item会没反应 return true; } return super.onTouchEvent(e); } }
看来对不一样的View处理触摸事件,得具体分析,照搬多是不行的事件