Skip to content

Commit

Permalink
fix(iOS): Fix updating bounds while changing interface orientation (#…
Browse files Browse the repository at this point in the history
…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 #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
  • Loading branch information
tboba authored May 8, 2024
1 parent 2a58846 commit 1e75e0c
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 0 deletions.
1 change: 1 addition & 0 deletions FabricTestExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import Test1802 from './src/Test1802';
import Test1829 from './src/Test1829';
import Test1844 from './src/Test1844';
import Test1864 from './src/Test1864';
import Test1970 from './src/Test1970';
import TestScreenAnimation from './src/TestScreenAnimation';
import Test1981 from './src/Test1981';
import Test2008 from './src/Test2008';
Expand Down
73 changes: 73 additions & 0 deletions FabricTestExample/src/Test1970.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button, StyleSheet, Text } from 'react-native';

const Stack = createNativeStackNavigator();

const Home = () => {
const navigation = useNavigation();

return (
<>
<Text>Home Screen - Portrait</Text>
<Button title="Next" onPress={() => navigation.navigate('Landscape')} />
</>
);
};

const Landscape = () => {
const navigation = useNavigation();

return (
<>
<Text>Landscape Screen</Text>
<Button title="Back" onPress={() => navigation.goBack()} />
</>
);
};

export default function App() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ animation: 'none', headerShown: false }}>
<Stack.Screen
name="Home"
component={Home}
options={{
orientation: 'portrait',
contentStyle: {
flex: 1,
backgroundColor: '#abc',
justifyContent: 'center',
alignItems: 'center',
},
}}
/>
<Stack.Screen
name="Landscape"
component={Landscape}
options={{
orientation: 'landscape',
contentStyle: {
flex: 1,
backgroundColor: '#cba',
justifyContent: 'center',
alignItems: 'center',
},
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
1 change: 1 addition & 0 deletions TestsExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import Test1802 from './src/Test1802';
import Test1829 from './src/Test1829';
import Test1844 from './src/Test1844';
import Test1864 from './src/Test1864';
import Test1970 from './src/Test1970';
import Test1981 from './src/Test1981';
import Test2008 from './src/Test2008';
import Test2048 from './src/Test2048';
Expand Down
73 changes: 73 additions & 0 deletions TestsExample/src/Test1970.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button, StyleSheet, Text } from 'react-native';

const Stack = createNativeStackNavigator();

const Home = () => {
const navigation = useNavigation();

return (
<>
<Text>Home Screen - Portrait</Text>
<Button title="Next" onPress={() => navigation.navigate('Landscape')} />
</>
);
};

const Landscape = () => {
const navigation = useNavigation();

return (
<>
<Text>Landscape Screen</Text>
<Button title="Back" onPress={() => navigation.goBack()} />
</>
);
};

export default function App() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ animation: 'none', headerShown: false }}>
<Stack.Screen
name="Home"
component={Home}
options={{
orientation: 'portrait',
contentStyle: {
flex: 1,
backgroundColor: '#abc',
justifyContent: 'center',
alignItems: 'center',
},
}}
/>
<Stack.Screen
name="Landscape"
component={Landscape}
options={{
orientation: 'landscape',
contentStyle: {
flex: 1,
backgroundColor: '#cba',
justifyContent: 'center',
alignItems: 'center',
},
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
4 changes: 4 additions & 0 deletions ios/RNSScreenStack.mm
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,10 @@ - (void)navigationController:(UINavigationController *)navigationController
{
[self emitOnFinishTransitioningEvent];
[RNSScreenWindowTraits updateWindowTraits];
// Because of the bug that caused view to have incorrect dimensions while changing the orientation,
// we need to signalize that it needs to be layouted.
// see https://github.com/software-mansion/react-native-screens/pull/1970
[_controller.view setNeedsLayout];
}
#endif

Expand Down

0 comments on commit 1e75e0c

Please sign in to comment.