Skip to content

Conversation

kligarski
Copy link
Contributor

Description

Adds orientation management for Tabs.

Closes https://github.com/software-mansion/react-native-screens-labs/issues/97.

Moved from https://github.com/software-mansion/react-native-screens-labs/pull/262.

Overriding supportedInterfaceOrientaitons for TabBarController and TabsScreenViewController is not enough. UIKit calls these methods only once and does not enforce orientation they return. UIKit asks root view controller more often - that's why we already swizzled supportedInterfaceOrientations to get access to return value from root UIViewController (from react-native) in ScreenStack implementation (useful article about UIKit's behavior).

I decided to use our own methods to handle orientation instead of overriding supportedInterfaceOrientations for tabs-related view controllers and use swizzled supportedInterfaceOrientation in root to return appropriate orientation mask to UIKit.

In ScreenStack, orientation: 'default' is mapped to UIInterfaceOrientationMaskAllButUpsideDown but this is correct only for iPhones (e.g. iPads use UIInterfaceOrientationMaskAll). There is no other option that maps to UIInterfaceOrientationMaskAllButUpsideDown.

In new implementation, I added options for all UIInterfaceOrientationMask enum values and changed 'default' into 'inherit' to use as default value. This value means that view controller does not have any preference for orientation. When root is asked for supportedInterfaceOrientations, it checks if their last child conforms to RNSOrientationProviding. If so, it asks the child view controller for orientation. These calls are propagated down the hierarchy with the last child having priority. If the last child returns Inherit, view controller above returns its preference. If root receives Inherit, it uses mask defined in Info.plist (docs), otherwise it maps received RNSOrientation into UIInterfaceOrientationMask.

For ScreenStack, we use old implementation of handling orientation at the screen level (we map result from its supportedInterfaceOrientations to RNSOrientation). Old stack does not support new props, including RNSOrientationInherit.

Example

UIViewController (React)
       |
       | last child view controller's orientation
       | or orientation from Info.plist
       |
RNSTabBarController
       |
       | selected view controller's orientation 
       | or RNSOrientationInherit
       |
RNSTabsScreenViewController
       |
       | last child view controller's orientation 
       | or orientation provided via prop (defaults to RNSOrientationInherit)
       |
RNSNavigationController
       |
       | top view controller's orientation 
       | or RNSOrientationInherit
       |
RNSScreen
       |
       | RNSOrientation mapped from UIInterfaceOrientationMask 
       | returned from supportedInterfaceOrientations (previous implementation)
       |
      ...

In the future, we need to implement orientation management for new Stack implementation as well as SplitView. This should be straightforward. Stack implementation will be a mix of old ScreenStack and new Tabs implementations. SplitView implementation should take into account orientation defined via prop at host controller.

Note

Changing orientation manually (editing and saving file) via config in TestBottomTabs.tsx seems buggy but it is due to "Refreshing..." bar in debug mode. If you change the prop in JS (e.g. with setInterval), it works as expected.

Manually In JS
Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-07-15.at.11.05.47.mov
Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-07-15.at.11.04.51.mov

Changes

  • add RNSOrientationProviding protocol
  • implement it for tabs and screenstack

Test code and steps to reproduce

Run example app and switch between tabs/screens in nested stack.

Checklist

  • Included code example that can be used to test this change
  • Ensured that CI passes

@kligarski kligarski force-pushed the @kligarski/gamma-orientation-tabs-screenstack branch from 742454b to 6f180f8 Compare August 5, 2025 07:28
@kligarski kligarski marked this pull request as draft August 5, 2025 07:30
@kligarski kligarski marked this pull request as ready for review August 5, 2025 08:35
@kligarski kligarski requested review from t0maboro and kkafar August 11, 2025 08:42
@kligarski kligarski merged commit 492efd6 into main Aug 14, 2025
9 checks passed
@kligarski kligarski deleted the @kligarski/gamma-orientation-tabs-screenstack branch August 14, 2025 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants