I am experimenting with integrating a Firebase-backed RecyclerView in a React Native app. With hardcoded data it works well, but upon inserting rows loaded dynamically and c
The root view in ReactNative is ReactRootView which onlayout
is an empty method.
when call notifyDatasetChanged
in RecyclerView, it's actually request layout
to relayout its children. And the layout method will call super.layout
to travel the whole view tree first. So that't a problem when the root view is ReactRootView.
You can manually call RecyclerView.onlayout(boolean changed, int l, int t, int r, int b)
to trigger its children relayout to make notifyDatasetChanged work.
The problem is that requestLayout
does not work well when the RecyclerView
is a native UI component.
The following hack made all those issues go away:
I now overwrite the requestLayout
method inside my RecyclerView
.
Then before any notify*
method, or even scrollToPosition
calls or any method that invokes a re-layout, I allow my custom requestLayout
method to force a re-layout.
The end result looks like this:
private boolean mRequestedLayout = false;
public void aMethodThatUpdatesStuff(int indexToUpdate, ReadableMap updatedChild) {
final SPAdapter adapter = (SPAdapter) getAdapter();
mRequestedLayout = false;
adapter.updateDataAtIndex(indexToUpdate, updatedChild); // <-- this runs notifyItemChanged inside
}
@Override
public void requestLayout() {
super.requestLayout();
// We need to intercept this method because if we don't our children will never update
// Check https://stackoverflow.com/questions/49371866/recyclerview-wont-update-child-until-i-scroll
if (!mRequestedLayout) {
mRequestedLayout = true;
this.post(new Runnable() {
@SuppressLint("WrongCall")
@Override
public void run() {
mRequestedLayout = false;
layout(getLeft(), getTop(), getRight(), getBottom());
onLayout(false, getLeft(), getTop(), getRight(), getBottom());
}
});
}
}