Evil Mouth's Blog

CoordinatorLayout+RecyclerView加载更多时自动滑动的问题

June 15, 2018

记录一下CoordinatorLayout+RecyclerView组合联动时,滑到底部触发加载更多并通过notifyItemRangeInserted添加数据时,RecyclerView会顺着继续滑动的问题。

问题 GIF

使用CoordinatorLayout联动RecyclerView的情况下(普通情况不会),加载更多是通过设置多Type的方式注入adapter实现的。当快速滑动RecyclerView时,通过notifyItemRangeInserted插入数据到尾部,则会发生下图所示的情况。

解决之路

焦点问题?

在大多数场景是没有使用CoordinatorLayout的,正常的使用RecyclerView是不会出现这种现象,所以一开始就觉得是CoordinatorLayout嵌套的焦点问题,焦点被RecyclerView抢夺导致自动滑动(Ps:以前见多了各种ScrollView嵌套的焦点问题)。所以给CoordinatorLayout做了焦点拦截,直接在布局文件设置属性

android:descendantFocusability="blocksDescendants"

但是并没有解决问题

之后试了半天布局修改,例如android:focusable="true" android:focusableInTouchMode="true"等都解决不了问题,只能上网搜搜了。。。

positionStart?

搜到的第一个类似问题,附带个链接 -> Link

这位码友也是遇到类似自动滑动的问题,也是添加数据后触发,只不过他的情况是他有个多type的头部,所以调用notifyItemRangeInserted时的positionStart+1,这也提醒我们打代码的时候得多注意,很多神奇的 bug 都是这样来的。。。

也不是解决方案

RecyclerView 设计初衷?

再搜到一个类似问题,再附带链接 -> Link

这次这位码友的情况跟我挺相似的,也是利用多type实现footer,利用这个footer实现加载更多的功能,同样插入数据会自动滑动。最佳回答是这样说的:

该码友在有footer的时候调用notifyItemRangeInserted(0, list.size())时,由于footer是唯一存在的第一条itemRecyclerView为了保持用户视觉体验、能继续看到footer,所以自动滑动到footer的位置。推荐该码友在list.size() == 0时候调用notifyDataSetChanged()代替

这一现象确实存在,也是平时需要注意的点,但也不是这次的解决方案

解决!!!

再之后找不到相关的问题了,也是自己看了下RecyclerView的源码,找到了个方法

recyclerview.stopScroll()

所以最后也是投机取巧的暂时解决这个问题,在插入数据之前停止滚动 (暂时无法从NestedScroll联动滑动机制解决这个问题,如果有大佬知道这个问题解决方案恳请告知一声,下方评论或 Email 我都可以,谢谢)

recyclerview.stopScroll();
adapter.addList(list);

public void addList(List<Object> list) {
    final int index = mList.size();
    mList.addAll(list);
    notifyItemRangeInserted(index, list.size());
}

— Evil Mouth