Children in a frozen `ScrollView` calls onLayout, but only on Android and not iOS
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.
https://github.com/software-mansion/react-freeze/assets/5456182/b8edd119-0133-4541-be00-e950f35750aa
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)
}
}