[Navigator] width is not updated when orientation is changed, so switch-animation stops halfway and component vanishes
See original GitHub issueI found a bug when you create a simple app that uses only the <Navigator />
component with iOS when you change the orientation from portrait to landscape. You will see that the back-animation (when switching states) keeps it old target-x-position to animate to.
I expect that the back-animation will stop at the far end/border of the landscape-screen (“outside” the view).
While trying to set the width/height to the view & navigator, which not solved it, I suspect that because it only happens in landscape mode the width of the navigator view is not updated when the orientation changes so the old target-value (x-position) is used to animate the old state to.
You can test it following these steps:
react-native init ORIENTATION
- copy this example into
index.ios.js
(will fail for React-Native 0.7.1
& 0.8.0-rc.2
)
Anyone have an idea where to look? I am not an native iOS developer, but any tips/fixes are welcome.
Issue Analytics
- State:
- Created 8 years ago
- Comments:11 (2 by maintainers)
I managed to hack together something that works. Basically I pass in the width and the height from the parent view of the Navigator using the style property. Then, in Navigator.js, I removed the maincontainer style, and replaced all instances of SCREEN_WIDTH, SCREEN_HEIGHT, SCENE_DISABLED_NATIVE_PROPS, and disabledScene, with equivalent objects containing props.style.width and props.style.height.
Props.style.width and props.style.height are set in the parent view (in my case, index.js) and get reset by onLayout.
This completely doesn’t address SceneConfig issues, but I’ll live with this for now.
There is a way to get it working properly without a need to change the Navigator’s source code. It doesn’t look very nice, but, in my opinion, it’s not a bad temporary workaround.
So, there are two issues which you need to deal with.
Proper resizing of scene views
In order to get your scenes properly resized after a device orientation has been changed, you can create custom scene configurations, where you could use a proper app layout width. Once your device orientation is changed, you can reset every scene with a new route stack and render the scenes using updated scene configs.
To do so, you can copy all of the styles you need for your scene transitions from the NavigatorSceneConfigs.js file (https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js), paste them into your custom scene configs, and replace all of the
SCREEN_WIDTH
andDimensions.get('window').width
occurrences with a passed width value. I preferred to keep all of the custom scene config related stuff in a separate file. You may have something like this if you would like to use HorizontalSwipeJump config option:Then, you need to call the specified above function within the
configureScene
property of your navigator:this.props.appLayout.width
should contain a relevant value of your layout width.If you use Redux to update the layout width, you can catch the moment of an orientation being changed and use the following code to reset every scene with a new stack of routes. In the following example, just one scene is added to the stack:
Next, we’ll fix the second issue which relates to styling disabled scenes.
Applying proper styles to disabled scenes
If you have a few routes in your stack, you will probably notice a rendering issue when you switch from a landscape view to portrait. A part of your next scene will be visible at the bottom of your current scene. The issue occurs due to the fact that all of the scenes, except for the current one, are hidden with CSS (
styles.disabledScene
, https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/Navigator.js#L114) which uses a layout height, that was evaluated just once in Navigator.js The indicated CSS is used within the_renderScene
function. So, you may consider overriding it with your code which uses an up-to-date layout height. To do so, you can extend the Navigator component with your own:Within your sceneNavigatorOverride.js file, you will need to have something like this:
That’s it! I hope it was helpful.
Please let me know if you have any questions.
Thanks @lazarmat and @zharley for cooperation and great job in figuring out the described above solution.