react-native-screens icon indicating copy to clipboard operation
react-native-screens copied to clipboard

iOS: Dismissing modal with swipe gesture has delayed status bar style update

Open samjusaitis opened this issue 2 years ago • 5 comments

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

samjusaitis avatar Feb 05 '22 09:02 samjusaitis

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

hirbod avatar Feb 11 '22 00:02 hirbod

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.

samjusaitis avatar Feb 11 '22 22:02 samjusaitis

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 UIViewControllers 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 avatar Feb 16 '22 10:02 WoLewicki

@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)

samjusaitis avatar Feb 25 '22 03:02 samjusaitis

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.

WoLewicki avatar Feb 28 '22 12:02 WoLewicki