Bug 复现
在滑动RecyclerView到一定位置,不显示RecyclerView的顶部Item时,调用notifyDataChanged()刷新RecyclerView 然后再滑动到顶部Item就会跳动闪烁.
滑动到顶部Item跳动原因
StaggeredGridLayoutManager中的LazySpanLookup保存了Item中的跨度,RecyclerView从底部滑动到顶部时,因为StaggeredGridLayoutMananger重写了onScrollStateChanged(),清空了LazySpanLookup中保存的跨度.调用链如下:onScrollStateChanged()→checkForGaps()→mLazySpanLookup.clear()清空保存的宽度Span后下次会重新布局,导致滑动到顶部的时候会有一个item跳动的效果.
static class LazySpanLookup {
private static final int MIN_SIZE = 10;
//保存Item的跨度
int[] mData;
List<FullSpanItem> mFullSpanItems;
}
调用StaggeredGridLayoutMananger.setGapStrategy(GAP_HANDLING_NONE)设置Item之间的间隙策略.当Item存在间隙时不自动重新排列布局.就不会导致顶部的Item跳动.这个方法如果不调用notifyDataChanged()更新界面就不会有问题.但是如果在底部调用notifyDataChanged()就会会引起顶部Item存在空白.
网上找到的方法都没有解决我的问题
1.RecyclerView高级进阶之优雅地解决瀑布流的两个神坑 - 掘金 (juejin.cn)
2.RecyclerView瀑布流空白、重新排序原因及解决办法 - 简书 (jianshu.com)
解决方法
//设置LayoutManagwer的空隙策略为不自动填充Item空白
layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
然后重写StaggeredGridLayoutManager的onItemUpadted()
/**
* 解决调用Adapter.notifyRangeChanged() Item显示错乱的问题
*/
public class SensorInfoLayoutManager extends StaggeredGridLayoutManager {
public SensorInfoLayoutManager(int spanCount, int orientation) {
super(spanCount, orientation);
}
@Override
public void onItemsUpdated(RecyclerView recyclerView, int positionStart,
int itemCount, Object payload) {
//空实现
//为了解决RecyclerView刷新界面Item顺序错乱
}
}
因为我的RecyclerView 的Item大小都是固定不变的,只需要更新Item的内容,不需要更新大小.这个方法能解决我的问题.
注意:如果刷新界面时,Item大小会改变,如果采用这个方法可能导致其他问题(这我没测试过)