回收视图中的 diffutil,使其在添加新项目时自动滚动



如果我们使用DiffUtil.Callback,并且

adapter.setItems(itemList);
diff.dispatchUpdatesTo(adapter);

我们如何确保添加新元素将滚动到该新位置。

我有一个案例,我看到项目消失了,并且在顶部创建了一个新元素作为第一个元素,但不可见。它隐藏在顶部,直到您向下滚动以使其可见。 在使用DiffUtil之前,我手动实现了这一点,在我知道我正在插入某个位置(顶部)之后,我可以滚动到。

有一种简单的方法可以做到这一点,如果项目插入到可查看区域之外,还可以保留用户的滚动位置:

import android.os.Parcelable;
Parcelable recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();
// apply diff result here (dispatch updates to the adapter)
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);              

使用此方法,如果将新项插入到用户可以看到它们的位置,则会使其可见,但如果将项插入视图之外,则会保留用户的视点。

您也可以使用dispatchUpdatesTo(ListUpdateCallback)方法。

因此,您可以实现一个ListUpdateCallback,它为您提供插入的第一个元素

class MyCallback implements ListUpdateCallback {
int firstInsert = -1;
Adapter adapter = null;
void bind(Adapter adapter) {
this.adapter = adapter;
}
public void onChanged(int position, int count, Object payload) {
adapter.notifyItemRangeChanged(position, count, payload);
}
public void onInserted(int position, int count) {
if (firstInsert == -1 || firstInsert > position) {
firstInsert = position;
}
adapter.notifyItemRangeInserted(position, count);
}
public void onMoved(int fromPosition, int toPosition) {
adapter.notifyItemMoved(fromPosition, toPosition);
}
public void onRemoved(int position, int count) {
adapter.notifyItemRangeRemoved(position, count);
}
}

然后手动滚动RecyclerView

myCallback.bind(adapter)
adapter.setItems(itemList);
diff.dispatchUpdatesTo(myCallback);
recycler.smoothScrollToPosition(myCallback.firstInsert);

我使用RecyclerView.AdapterDataObserver来检测何时添加了新项目,然后滚动到列表顶部;

adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
recycleView.smoothScrollToPosition(0);
}
});

它对我有用

recyclerview.setItemAnimator(new DefaultItemAnimator() {
@Override
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull List<Object> payloads) {
return true;
}
});
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
//when a new item is inserted
if (positionStart == 0 && itemCount == 1/*number of item inserted*/) {
scrollToFirst();
mRecordListAdapter.unregisterAdapterDataObserver(this);
}
}
});

private void scrollToFirst() {
//when an item is added to the first position
//however as per the recyclerview the view is added out of the visible area
//(as the 2nd item after update was the first item before list update)
//thus the newly item won't be visible
//Therefore if the 1st item is visible then scroll to the first pos
//so that the newly item can be visible when inserted
var position = ((LinearLayoutManager) recyclerview.getLayoutManager()).findFirstCompletelyVisibleItemPosition();
if (position < 1 && position != RecyclerView.NO_POSITION) {
recyclerview.scrollToPosition(0);
}
}

最新更新