If we use DiffUtil.Callback
, and do
adapter.setItems(itemList);
diff.dispatchUpdatesTo(adapter);
how can we make sure that adding of new elements will scroll to that new position.
I have a case where I see item disappear, and a new one is created as a first element at the top, but not visible. It is hidden on top until you scroll down to make it visible.
Before using DiffUtil
, I was implementing this manually, and after I knew I was inserting at some position (on top) I could scroll to.
There's an easy way to do this that also preserves the user's scroll position if items are inserted outside the viewable area:
import android.os.Parcelable;
Parcelable recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();
// apply diff result here (dispatch updates to the adapter)
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
Using this approach, the new items are made visible if they are inserted where the user can see them -- but the user's viewpoint is preserved if the items are inserted outside of view.
You have a dispatchUpdatesTo(ListUpdateCallback)
method to use as well.
So you could just implement a ListUpdateCallback
which gives you the first element inserted
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);
}
}
and then just scroll the RecyclerView
manually
myCallback.bind(adapter)
adapter.setItems(itemList);
diff.dispatchUpdatesTo(myCallback);
recycler.smoothScrollToPosition(myCallback.firstInsert);
I used RecyclerView.AdapterDataObserver
to detect when new items were added, and then scroll to the top of my list;
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
recycleView.smoothScrollToPosition(0);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With