NestedRecyclerView
NestedRecyclerView copied to clipboard
有两个问题
rt 1.向上滑动列表时初次滑动会有卡顿问题 2.当下方Recyclerview全部显示的时候,在快速fling的过程中,底部Recyclerview在未全部显示(滑动到顶部时)就已经将手势交给外层列表开始滑动头部Recyclerview
第一个是因为创建新视图的原因,可以放在子线程。
第二个是因为父控件的onInterceptTouchEvent拦截出的问题,定位原因在Recyclerview里面
// Clear the active onInterceptTouchListener. None should be set at this time, and if one // is, it's because some other code didn't follow the standard contract. mInterceptingOnItemTouchListener = null; if (findInterceptingOnItemTouchListener(e)) { cancelScroll(); return true; }
这里面手动设置为true了,需要自己判断子控件是否滑动到顶部,否则父控件不做拦截,两个问题都已解决
第二个问题有两种解决方法: 一:子控件通知父控件不要干涉我的手势事件:
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
/*
通知父view是否可以截获事件
*/
final boolean isScrollUp = !canScrollVertically(-1);
if (isScrollUp) {
/*
同父的此重写方法return super.onInterceptTouchEvent(v)
*/
getParent().requestDisallowInterceptTouchEvent(false);
Log.d("子dispatchTouchEvent", "子滑动到顶部");
} else {
Log.d("子dispatchTouchEvent", "子没有滑动到顶部,可以继续向上滑动");
/*
同父的此重写方法的return false
*/
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.onInterceptTouchEvent(e);
}
二:父控件中直接去不拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
final boolean intercept = super.onInterceptTouchEvent(e);
if (e != null) {
final int action = e.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: {
Log.d("父dispatchTouchEvent", "ACTION_DOWN");
}
case MotionEvent.ACTION_MOVE: {
Log.d("父dispatchTouchEvent", "ACTION_MOVE");
}
case MotionEvent.ACTION_CANCEL: {
Log.d("父dispatchTouchEvent", "ACTION_CANCEL");
}
case MotionEvent.ACTION_UP: {
Log.d("父dispatchTouchEvent", "ACTION_UP");
}
}
}
RecyclerView childRecyclerView = findNestedScrollingChildRecyclerView();
if (childRecyclerView != null) {
boolean isScrollUp = !childRecyclerView.canScrollVertically(-1);
if (isScrollUp) {
Log.d("父dispatchTouchEvent", "子滑动到顶部");
} else {
Log.d("父dispatchTouchEvent", "子没有滑动到顶部,可以继续向上滑动");
return false;
}
}
if (intercept) {
Log.d("父dispatchTouchEvent", "父控件拦截手势了");
} else {
Log.d("父dispatchTouchEvent", "父控件未拦截手势");
}
return intercept;
}
上面两种方法有bug,第二种方法暂时废弃,第一种方法需要加上判断,如下,否则viewpager划不动 如下:
private var oldX = 0F
private var oldY = 0F
private var newX = 0F
private var newY = 0F
override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
val intercept = super.onInterceptTouchEvent(e)
if (e != null) {
val action = e.action
when (action) {
MotionEvent.ACTION_DOWN -> run {
oldX = e.x
oldY = e.y
Log.d("dispatchTouchEvent", "parent ACTION_DOWN")
}
MotionEvent.ACTION_MOVE -> run {
newX = e.x
newY = e.y
Log.d(
"onInterceptTouchEvent",
"onInterceptTouchEvent parent oldX:" + oldX + ",oldY:" + oldY
)
Log.d(
"onInterceptTouchEvent",
"onInterceptTouchEvent parent newX:" + newX + ",newY:" + newY
)
oldX = newX
oldY = newY
}
MotionEvent.ACTION_CANCEL -> run {
Log.d("dispatchTouchEvent", "parent ACTION_CANCEL")
}
MotionEvent.ACTION_UP -> run {
Log.d("dispatchTouchEvent", "parent ACTION_UP")
}
}
}
val childRecyclerView: RecyclerView? = findNestedScrollingChildRecyclerView()
if (childRecyclerView != null) {
val isScrollUp = !childRecyclerView.canScrollVertically(-1)
if (isScrollUp) {
Log.d("dispatchTouchEvent", "parent 子滑动到顶部")
} else {
Log.d("dispatchTouchEvent", "parent 子没有滑动到顶部,可以继续向上滑动")
/*
不再这里去处理手势了,放在子中,不用去查询view,提高效率
如果x轴偏移量大于y轴此时父控件先去处理,之后再交给子控件
*/
return if (abs(newX - oldX) > abs(newY - oldY)) {
intercept
} else {
false
}
}
}
if (intercept) {
Log.d("dispatchTouchEvent", "parent 父控件拦截手势了")
} else {
Log.d("dispatchTouchEvent", "parent 父控件未拦截手势")
}
return intercept
}
第二种方法暂时废弃,第一种方法需要加上判断
两种方法(外部拦截和 内部拦截)都可以进行加入判断使 ViewPager 滑动。
这里还有两个问题,就是三层嵌套滑动的fling还是有问题,等待解决后会提交解决方案 另外一个问题是三层嵌套滑动,如果父Recyclerview滑动到底部,子Recyclerview viewpager切换会有问题