From 913fdbb51162d788dadcadbaec7c48a6735b4941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Du=C5=BCy?= <91994767+alduzy@users.noreply.github.com> Date: Mon, 7 Oct 2024 22:23:31 +0200 Subject: [PATCH] fix(iOS): header subviews layout on tab change (#2385) ## Description This PR intents to fix header subviews incorrect layout when changing tabs. The previous solution did layout the subviews correctly in the test cases, but triggered an undesirable `layoutIfNeeded` when going back from tab to tab. In such case the navigation layout happened without updating subview's layout metrics. Moving the logic to subview resolves the issue as the re-layout is now triggered only when subview's layout metrics are updated. Related fixes from the past: https://github.com/software-mansion/react-native-screens/pull/2316, https://github.com/software-mansion/react-native-screens/pull/2248 ## Changes - combined `Test2231.tsx` with `Test432.tsx` to create comprehensive test case - moved re-layout logic to subview ## Screenshots / GIFs ### Before ![Screenshot 2024-10-04 at 10 10 15](https://github.com/user-attachments/assets/1a8a747e-fe1d-4b03-ba63-1891732d7d77) ### After ![Screenshot 2024-10-04 at 10 09 37](https://github.com/user-attachments/assets/68b3554f-d67d-47f4-946d-ace60e1bbf83) ## Test code and steps to reproduce - Use `Test432.tsx` repro ## Checklist - [x] Included code example that can be used to test this change - [x] Ensured that CI passes --- apps/src/tests/Test2231.tsx | 56 ------------ apps/src/tests/Test432.tsx | 137 +++++++++++++++++++---------- apps/src/tests/index.ts | 1 - ios/RNSScreenStackHeaderConfig.mm | 3 - ios/RNSScreenStackHeaderSubview.mm | 24 +++++ 5 files changed, 115 insertions(+), 106 deletions(-) delete mode 100644 apps/src/tests/Test2231.tsx diff --git a/apps/src/tests/Test2231.tsx b/apps/src/tests/Test2231.tsx deleted file mode 100644 index 9449ffc3ff..0000000000 --- a/apps/src/tests/Test2231.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import React, { useLayoutEffect, useState } from 'react'; -import { View } from 'react-native'; - -import { SettingsSwitch, Square } from '../shared'; -import { NavigationContainer } from '@react-navigation/native'; - -const SettingsScreen = ({ navigation }: any) => { - const [hasLeftItem, setHasLeftItem] = useState(false); - - const square1 = (props: { tintColor?: string }) => ( - - {hasLeftItem && } - - - ); - - const square2 = (props: { tintColor?: string }) => ( - - ); - - useLayoutEffect(() => { - navigation.setOptions({ - headerRight: square1, - headerTitle: undefined, - headerLeft: hasLeftItem ? square2 : undefined, - headerBackTitleVisible: false, - }); - }, [navigation, hasLeftItem]); - - return ( - - ); -}; - -const Stack = createNativeStackNavigator(); - -const App = () => ( - - - - - -); - -export default App; diff --git a/apps/src/tests/Test432.tsx b/apps/src/tests/Test432.tsx index 8274bfd299..f58bd3b752 100644 --- a/apps/src/tests/Test432.tsx +++ b/apps/src/tests/Test432.tsx @@ -1,37 +1,36 @@ -import { Pressable, View, Button, Text } from 'react-native'; - -import { NavigationContainer, useNavigation } from '@react-navigation/native'; +import { View, Button, Text } from 'react-native'; +import { NavigationContainer } from '@react-navigation/native'; import { NativeStackScreenProps, createNativeStackNavigator, } from '@react-navigation/native-stack'; -import React, { useCallback } from 'react'; +import React, { useEffect, useLayoutEffect, useState } from 'react'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { Square } from '../shared'; -type RootStackParamList = { +type StackParamList = { Home: undefined; + Details: undefined; Settings: undefined; + Info: undefined; }; -type RootStackScreenProps = - NativeStackScreenProps; -const HomeScreen = ({ navigation }: RootStackScreenProps<'Home'>) => { - const [x, setX] = React.useState(false); - React.useEffect(() => { - navigation.setOptions({ - headerBackVisible: !x, - headerRight: x - ? () => ( - - ) - : () => ( - - ), - }); - }, [navigation, x]); +type StackScreenProps = NativeStackScreenProps< + StackParamList, + T +>; +const HomeScreen = ({ navigation }: StackScreenProps<'Home'>) => { return ( -