react-native-screens
react-native-screens copied to clipboard
iOS: Dismissing modal with swipe gesture has delayed status bar style update
Description
I am using a screen with presentation: 'modal' on iOS, and have StatusBar components in both the modal and underlying screens to set their status bar styles to 'light-content' and 'dark-content' respectively. This works smoothly when navigating to the modal screen and returning to the underlying screen via a navigation.goBack link (see second video below). However, when navigating back to the underlying screen via a swipe down gesture, there is a noticeable delay in the updating of the status bar style (see first video below).
Screenshots
Notice the delay in the status bar style returning to its 'dark-content' style after dismissing the modal: https://user-images.githubusercontent.com/47904203/152635313-b044f2fa-fcee-41c3-98b4-612d879e407d.mp4
Here the status bar style updates as expected, as soon as the user taps the Back Home button: https://user-images.githubusercontent.com/47904203/152635529-0ccf256c-61ab-419d-8975-09fd2bb70b23.mp4
Steps To Reproduce
(see above explanation or below Snack)
Expected behavior
That the status bar style would update as soon as the user dismisses the modal screen via the swipe down gesture. This is what happens elsewhere in native iOS apps.
Actual behavior
There is a delay in the status bar style updating following a swipe down to dismiss gesture.
Reproduction
https://snack.expo.dev/@sjusaitis/modal-status-bar-example
Platform
- [x] iOS
- [ ] Android
- [ ] Web
- [ ] Windows
- [ ] tvOS
Workflow
- [x] Managed workflow (using Expo dev client)
- [ ] Bare workflow
Package versions
package | version |
---|---|
react-native | 0.64.3 |
@react-navigation/native | 6.0.8 |
@react-navigation/native-stack | 6.4.1 |
react-native-screens | 3.10.2 |
react-native-safe-area-context | 3.3.2 |
expo | 44.0.2 |
IIRC, you need to set expo.ios.infoPlist
to UIViewControllerBasedStatusBarAppearance: true
.
Unfortunately, this is currently breaking the whole app within Expo, even though it should actually work in custom-dev-client (it is not though)
I filed an issue for this over a month ago, without any response so far. https://github.com/expo/expo/issues/15801
Thanks for the suggestion @hirbod.
You are right, setting UIViewControllerBasedStatusBarAppearance: true
enables automatic adjustment of the status bar style and doesn't require using any StatusBar components! However, as you mentioned this doesn't work in Expo Go, or Expo custom dev client. Also, enabling UIViewControllerBasedStatusBarAppearance: true
means you can't use the StatusBar component anywhere in your app AFAIK.
As the React Navigation docs recommend the approach of using StatusBar components with native stack to manage status bar style based on route, this really should work smoothly without needing to set UIViewControllerBasedStatusBarAppearance: true
.
It is a behavior of StatusBar
component and we can't do anything about it unfortunately. I added ability to control the statusBar
from the Screen
component, which should work on all navigators, not only native-stack
, with this PR: https://github.com/react-navigation/react-navigation/pull/9458. It automatically handles e.g. modals. But, as @hirbod mentioned, it uses different approach than the react-native
's StatusBar
since Screen
are UIViewController
s and need UIViewControllerBasedStatusBarAppearance: true
. Since there is nothing more to be done on this library's side, can I close this? Or am I missing something?
@WoLewicki it seems there is a noticeable delay in the underlying screen receiving focus when a user dismisses a modal via a swipe down gesture. This coincides with the delay in the StatusBar component updating the status bar style.
See the video below. The modal is first opened then closed via a button that calls navigation.goBack()
. This returns focus to the underlying screen immediately (note the 'Focussed'/'Unfocussed' text updated from the result of a useIsFocused
hook). On the second time, the modal is opened then closed using a swipe gesture. Here the focus is noticeable delayed to the underlying screen. And I'm guessing this is why the StatusBar component is also delayed in updating the status bar style.
https://user-images.githubusercontent.com/47904203/155650144-cc09d0b5-b19e-417b-99ec-f3106717b3e4.MP4
(Video based on updated Snack: https://snack.expo.dev/@sjusaitis/modal-status-bar-example)
Yeah, that is one of the reasons why using native option is better since it handles change of status bar automatically for modals. The reason why this happens here is probably that calling navigation.goBack()
immediately updates React children and changes the focused child, while dismissing modal natively calls a native method which is then sent to JS, so it is slower.