Skip to content

Commit 995aae9

Browse files
tbobaja1ns
authored andcommitted
fix(iOS): Fix updating bounds while changing interface orientation (software-mansion#1970)
## Description Currently while trying to change the interface orientation there's a bug that doesn't layout the next screen, causing the old frame to remain (which means that the next screen will be rotated regarding to the previous orientation. This PR fixes that problem by calling `[_controller.view setNeedsLayout]` on the `navigationController`, where the view is being rotated. When I was testing this PR I also came to another solution of setting the frame in `viewWillTransitionToSize` but I didn't spot any differences between one solution and this one. ```objc - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; #ifdef RCT_NEW_ARCH_ENABLED [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> coordinator) { self.screenView.frame = CGRectMake(0, 0, size.width, size.height); } completion:^(id<UIViewControllerTransitionCoordinatorContext> coordinator) { [self.screenView setNeedsLayout]; }]; #endif } ``` I've also tried to make a workaround of a reaaaally old bug in React Native: facebook/react-native#16060, but unfortunately I failed with that 😕 Closes software-mansion#1738. ## Changes - Adds call to `setNeedsLayout` during the interface orientation ## Screenshots / GIFs ### Before https://github.com/software-mansion/react-native-screens/assets/23281839/bcc366ab-9757-4a31-89e0-241c22cdd5c6 ### After https://github.com/software-mansion/react-native-screens/assets/23281839/6634379a-2697-46a3-aed6-3cb156616817 ## Test code and steps to reproduce You can find in this PR `Test1970.tsx` that contains test test I've tested while making this change. ## Checklist - [X] Included code example that can be used to test this change - [x] Ensured that CI passes
1 parent bd1d718 commit 995aae9

File tree

5 files changed

+152
-0
lines changed

5 files changed

+152
-0
lines changed

FabricTestExample/App.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ import Test1802 from './src/Test1802';
9090
import Test1829 from './src/Test1829';
9191
import Test1844 from './src/Test1844';
9292
import Test1864 from './src/Test1864';
93+
import Test1970 from './src/Test1970';
9394
import TestScreenAnimation from './src/TestScreenAnimation';
9495
import Test1981 from './src/Test1981';
9596
import Test2008 from './src/Test2008';

FabricTestExample/src/Test1970.jsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { NavigationContainer, useNavigation } from '@react-navigation/native';
2+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
3+
import { Button, StyleSheet, Text } from 'react-native';
4+
5+
const Stack = createNativeStackNavigator();
6+
7+
const Home = () => {
8+
const navigation = useNavigation();
9+
10+
return (
11+
<>
12+
<Text>Home Screen - Portrait</Text>
13+
<Button title="Next" onPress={() => navigation.navigate('Landscape')} />
14+
</>
15+
);
16+
};
17+
18+
const Landscape = () => {
19+
const navigation = useNavigation();
20+
21+
return (
22+
<>
23+
<Text>Landscape Screen</Text>
24+
<Button title="Back" onPress={() => navigation.goBack()} />
25+
</>
26+
);
27+
};
28+
29+
export default function App() {
30+
return (
31+
<NavigationContainer>
32+
<Stack.Navigator
33+
initialRouteName="Home"
34+
screenOptions={{ animation: 'none', headerShown: false }}>
35+
<Stack.Screen
36+
name="Home"
37+
component={Home}
38+
options={{
39+
orientation: 'portrait',
40+
contentStyle: {
41+
flex: 1,
42+
backgroundColor: '#abc',
43+
justifyContent: 'center',
44+
alignItems: 'center',
45+
},
46+
}}
47+
/>
48+
<Stack.Screen
49+
name="Landscape"
50+
component={Landscape}
51+
options={{
52+
orientation: 'landscape',
53+
contentStyle: {
54+
flex: 1,
55+
backgroundColor: '#cba',
56+
justifyContent: 'center',
57+
alignItems: 'center',
58+
},
59+
}}
60+
/>
61+
</Stack.Navigator>
62+
</NavigationContainer>
63+
);
64+
}
65+
66+
const styles = StyleSheet.create({
67+
container: {
68+
flex: 1,
69+
backgroundColor: '#fff',
70+
alignItems: 'center',
71+
justifyContent: 'center',
72+
},
73+
});

TestsExample/App.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ import Test1802 from './src/Test1802';
9393
import Test1829 from './src/Test1829';
9494
import Test1844 from './src/Test1844';
9595
import Test1864 from './src/Test1864';
96+
import Test1970 from './src/Test1970';
9697
import Test1981 from './src/Test1981';
9798
import Test2008 from './src/Test2008';
9899
import Test2048 from './src/Test2048';

TestsExample/src/Test1970.jsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { NavigationContainer, useNavigation } from '@react-navigation/native';
2+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
3+
import { Button, StyleSheet, Text } from 'react-native';
4+
5+
const Stack = createNativeStackNavigator();
6+
7+
const Home = () => {
8+
const navigation = useNavigation();
9+
10+
return (
11+
<>
12+
<Text>Home Screen - Portrait</Text>
13+
<Button title="Next" onPress={() => navigation.navigate('Landscape')} />
14+
</>
15+
);
16+
};
17+
18+
const Landscape = () => {
19+
const navigation = useNavigation();
20+
21+
return (
22+
<>
23+
<Text>Landscape Screen</Text>
24+
<Button title="Back" onPress={() => navigation.goBack()} />
25+
</>
26+
);
27+
};
28+
29+
export default function App() {
30+
return (
31+
<NavigationContainer>
32+
<Stack.Navigator
33+
initialRouteName="Home"
34+
screenOptions={{ animation: 'none', headerShown: false }}>
35+
<Stack.Screen
36+
name="Home"
37+
component={Home}
38+
options={{
39+
orientation: 'portrait',
40+
contentStyle: {
41+
flex: 1,
42+
backgroundColor: '#abc',
43+
justifyContent: 'center',
44+
alignItems: 'center',
45+
},
46+
}}
47+
/>
48+
<Stack.Screen
49+
name="Landscape"
50+
component={Landscape}
51+
options={{
52+
orientation: 'landscape',
53+
contentStyle: {
54+
flex: 1,
55+
backgroundColor: '#cba',
56+
justifyContent: 'center',
57+
alignItems: 'center',
58+
},
59+
}}
60+
/>
61+
</Stack.Navigator>
62+
</NavigationContainer>
63+
);
64+
}
65+
66+
const styles = StyleSheet.create({
67+
container: {
68+
flex: 1,
69+
backgroundColor: '#fff',
70+
alignItems: 'center',
71+
justifyContent: 'center',
72+
},
73+
});

ios/RNSScreenStack.mm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,10 @@ - (void)navigationController:(UINavigationController *)navigationController
923923
{
924924
[self emitOnFinishTransitioningEvent];
925925
[RNSScreenWindowTraits updateWindowTraits];
926+
// Because of the bug that caused view to have incorrect dimensions while changing the orientation,
927+
// we need to signalize that it needs to be layouted.
928+
// see https://github.com/software-mansion/react-native-screens/pull/1970
929+
[_controller.view setNeedsLayout];
926930
}
927931
#endif
928932

0 commit comments

Comments
 (0)