From 7d3205eddfc02b09f7dc7d88a52208b7d8e6ca58 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 27 Mar 2025 13:25:44 +0100 Subject: [PATCH 1/2] Do not send initial natively sized frame of HeaderSubview from HT to ST When setting subviews via `setOptions` from `useEffect` hook in a component, the first frame received might be computed by native layout & completely invalid (zero height). RN layout is the source of a subview **size** (not origin). When we send such update with zero height Yoga might (or might not, depending on exact update timing in relation to other ongoing commits / layouts) set the subview height to 0! This causes the subview to become invisible & we want to avoid that. This had not been a problem before #2696, because we would filter out this kind of frame in the `setSize` guard in the `ComponentDescriptor.adopt` method of the `HeaderSubview`. #2696 allowed for zero-sized frames for other, unrelated reason & we must allow these as long as they come from React Native layout & not native one. --- .../rnscreens/ScreenStackHeaderSubview.kt | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt index 4a3f24ba50..e4fdc49d5b 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt @@ -10,6 +10,14 @@ class ScreenStackHeaderSubview( ) : FabricEnabledHeaderSubviewViewGroup(context) { private var reactWidth = 0 private var reactHeight = 0 + + /** + * Semantics: true iff we **believe** that SurfaceMountingManager has measured this view during mount item + * execution. We recognize this case by checking measure mode in `onMeasure`. If Androidx + * happens to use `EXACTLY` for both dimensions this property might convey invalid information. + */ + private var isReactSizeSet = false + var type = Type.RIGHT val config: ScreenStackHeaderConfig? @@ -22,9 +30,10 @@ class ScreenStackHeaderSubview( if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY ) { - // dimensions provided by react + // dimensions provided by react (with high probability) reactWidth = MeasureSpec.getSize(widthMeasureSpec) reactHeight = MeasureSpec.getSize(heightMeasureSpec) + isReactSizeSet = true val parent = parent if (parent != null) { forceLayout() @@ -44,7 +53,15 @@ class ScreenStackHeaderSubview( if (changed && BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { val width = r - l val height = b - t - updateSubviewFrameState(width, height, l, t) + + // When setting subviews via `setOptions` from `useEffect` hook in a component, the first + // frame received might be computed by native layout & completely invalid (zero height). + // RN layout is the source of subview **size** (not origin) & we need to avoid sending + // this native size to ST. Doing otherwise might lead to problems. + // See: TODO: PR LINK + if (isReactSizeSet) { + updateSubviewFrameState(width, height, l, t) + } } } From 068b0af4df74039bb71a8e377671e9d9f68c3893 Mon Sep 17 00:00:00 2001 From: Kacper Kafara Date: Thu, 27 Mar 2025 14:37:16 +0100 Subject: [PATCH 2/2] Update PR link --- .../java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt index e4fdc49d5b..f2dfcfa4eb 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubview.kt @@ -58,7 +58,7 @@ class ScreenStackHeaderSubview( // frame received might be computed by native layout & completely invalid (zero height). // RN layout is the source of subview **size** (not origin) & we need to avoid sending // this native size to ST. Doing otherwise might lead to problems. - // See: TODO: PR LINK + // See: https://github.com/software-mansion/react-native-screens/pull/2812 if (isReactSizeSet) { updateSubviewFrameState(width, height, l, t) }