Children in a frozen `ScrollView` calls onLayout, but only on Android and not iOS
Opened this issue · 1 comments
When freezing a ScrollView
in Android, the children of the ScrollView
triggers onLayout
with width
, height,
x, and
y` all being 0. The main issue here is that it happens on only Android and not iOS. Ideally it would not happen on either platform.
Screen.Recording.2023-12-12.at.6.34.22.PM.mov
Sample code can be found here: https://github.com/tpcstld/react-native-test/tree/tpcstld/freeze-android
Steps to Repro:
- Open the app
- Click on Toggle Freeze
Observe that the last recorded height and width change on Android, but not iOS.
+1. as a result of this, if you have a RecyclerView
(and perhaps other virtualized list components) inside the frozen component, un-freezing can result in the list losing its scroll position because child views can change height if they are set to width: MATCH_PARENT
and height: WRAP_CONTENT
.
as a workaround, it is possible to override onMeasure
in the child views of your list and do something like this, but it's a bit hacky and requires subclassing View
on the native side:
// subclass View
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val parent = parent
val shouldUseCachedMeasurements =
parent != null && parent.measuredWidth == 0
&& View.MeasureSpec.getMode(widthMeasureSpec) == View.MeasureSpec.EXACTLY
}
if (shouldUseCachedMeasurements) {
val previouslyMeasuredWidth = measuredWidth
val previouslyMeasuredHeight = measuredHeight
super.onMeasure(
View.MeasureSpec.makeMeasureSpec(previouslyMeasuredWidth, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(previouslyMeasuredHeight, View.MeasureSpec.EXACTLY),
)
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}