Skip to content

Commit 5cd3b11

Browse files
authored
fix(iOS): header left and right layout on fabric (#2248)
## Description This PR fixes the header layout mismatch when updating both `headerLeft` and `headerRight` options simultaneously using `navigation.setOptions`. Fixes #2231 . ## Changes - Forced subview to re-layout when updating layoutMetrics - added `Test2231.tsx` repro ## Screenshots / GIFs ### Before ![Screenshot 2024-07-16 at 12 05 14](https://github.com/user-attachments/assets/37a5a77d-1cd5-457f-901e-9dd5b4065a8f) ### After ![Screenshot 2024-07-16 at 12 04 49](https://github.com/user-attachments/assets/025db807-ef6d-46f2-b4c0-cd9f06e03d93) ## Test code and steps to reproduce - Use `Test2231.tsx` repro ## Checklist - [x] Ensured that CI passes
1 parent c70f23b commit 5cd3b11

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

apps/src/tests/Test2231.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
2+
import React, { useLayoutEffect, useState } from 'react';
3+
import { View } from 'react-native';
4+
5+
import { SettingsSwitch, Square } from '../shared';
6+
import { NavigationContainer } from '@react-navigation/native';
7+
8+
const SettingsScreen = ({ navigation }: any) => {
9+
const [hasLeftItem, setHasLeftItem] = useState(false);
10+
11+
const square1 = (props: { tintColor?: string }) => (
12+
<View style={{ gap: 8, flexDirection: 'row' }}>
13+
{hasLeftItem && <Square {...props} color="green" size={20} />}
14+
<Square {...props} color="green" size={20} />
15+
</View>
16+
);
17+
18+
const square2 = (props: { tintColor?: string }) => (
19+
<Square {...props} color="red" size={20} />
20+
);
21+
22+
useLayoutEffect(() => {
23+
navigation.setOptions({
24+
headerRight: square1,
25+
headerTitle: undefined,
26+
headerLeft: hasLeftItem ? square2 : undefined,
27+
headerBackTitleVisible: false,
28+
});
29+
}, [navigation, hasLeftItem]);
30+
31+
return (
32+
<SettingsSwitch
33+
label="Left item"
34+
value={hasLeftItem}
35+
onValueChange={setHasLeftItem}
36+
/>
37+
);
38+
};
39+
40+
const Stack = createNativeStackNavigator();
41+
42+
const App = () => (
43+
<NavigationContainer>
44+
<Stack.Navigator>
45+
<Stack.Screen
46+
name="Settings"
47+
component={SettingsScreen}
48+
options={{
49+
headerTintColor: 'hotpink',
50+
}}
51+
/>
52+
</Stack.Navigator>
53+
</NavigationContainer>
54+
);
55+
56+
export default App;

apps/src/tests/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,6 @@ export { default as Test2184 } from './Test2184';
104104
export { default as Test2223 } from './Test2223';
105105
export { default as Test2227 } from './Test2227';
106106
export { default as Test2229 } from './Test2229';
107+
export { default as Test2231 } from './Test2231';
107108
export { default as TestScreenAnimation } from './TestScreenAnimation';
108109
export { default as TestHeader } from './TestHeader';

ios/RNSScreenStackHeaderSubview.mm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ - (void)updateLayoutMetrics:(const react::LayoutMetrics &)layoutMetrics
7272
self);
7373
} else {
7474
self.bounds = CGRect{CGPointZero, frame.size};
75+
// We're forcing the parent view to layout this subview with correct frame size,
76+
// see: https://github.com/software-mansion/react-native-screens/pull/2248
77+
[self.superview layoutIfNeeded];
7578
}
7679
}
7780

0 commit comments

Comments
 (0)