react-navigation / rfcs

RFCs for changes to React Navigation
Other
88 stars 16 forks source link

StatusBar configuration in navigator config #19

Open brentvatne opened 6 years ago

brentvatne commented 6 years ago

I have a plan for handling part of this myself. Which may not work for everyone, but might be useful for coming up with ideas.

For me I'm following Material Design with translucent headers. The primary StatusBar properties I need to control are barStyle and backgroundColor so they are compatible with the background color of the header (or the page background if there is no header). I'm working on a library for handling Material Design in React Native and I plan to build a header component anyways – to extend React Navigation's Header so it follows Material Design closer and can handle some of the Material Design patterns that React Navigation doesn't implement. So my plan is to just make the Header component handle the StatusBar automatically, calculating the correct barStyle and backgroundColor based on the current background color for the app bar.

via @dantman in https://github.com/react-navigation/react-navigation/issues/11

Related feature request: https://react-navigation.canny.io/feature-requests/p/control-statusbar-config-for-screens-in-navigationoptions

satya164 commented 6 years ago

Now that we have focus and blur events, it shouldn't be very hard to build an HOC which can manage status bar automatically.

ericvicenti commented 6 years ago

I was picturing something like this in the screen navigationOptions:

DarkModeScreen.navigationOptions = ({ navigation }) => ({
  statusBarStyle: navigation.params.darkMode ? 'light' : 'default',
  statusBarVisible: true,
  title: 'Im a screen with toggleable dark mode',
  // I'm not sure if this is a thing yet, but it would also be handy:
  headerColor:  navigation.params.darkMode ? 'black' : undefined,
});

@brentvatne, is this the sort of thing you had in mind? I'm not sure how the API would look like with a HOC.

brentvatne commented 6 years ago

Exactly @ericvicenti. I think this is important enough that it's worth building into navigationOptions. We probably need to expose a couple more options -- for animation type and color 😅 (Android gives more control over color than just light/dark)

grabbou commented 6 years ago

With Screen being a component, this could be as easy as allowing statusBar prop to receive an instance of StatusBar.

ivosabev commented 6 years ago

What is the status of this, sounds a simple fix?

brentvatne commented 5 years ago

like most things it's much more complex than it seems like on the surface. if anyone wants to work on this i can fill you in on the nuances and we can talk through them

khagesh commented 5 years ago

Not sure if this is correct place to comment about Status bar different solutions. Please pardon if not correct place. We also faced this issue in our app. We tried following options:

  1. Render <StatusBar barStyle="light-content" backgroundColor="red"> inside render() method. But there were some component that did not re-render when we came back to a screen. So users were stuck with wrong status bar color. Then we added navigation as prop so that navigation prop changes to trigger render and removed our scu optimization for those components that did not render.
  2. Created our own <CustomHeader /> component (extending ReactNavigation's header) that used to take header's background color, and then set StatusBar background color. For barStyle, we used npm package color, and used Color(headerColor).isLight() ? "dark-content" : "light-content", and then added memoization on top of this function. It worked fine for most screens, but there were few screens that did not have Header at all and for those we used to resort to a hack that works on each screen separately.
  3. We created a central config on app.js level, and used onNavigationStateChange and then call updateStatusBar function on the basis of routeName currently active. This allowed us to handle many scenarios. But people used to forget to update status bar color, route name to status bar mapping, adding new routes needs to be changed at different place than that screen or that particular screen file. Since these files were different, changing color of Header did not change color of status bar. We even added a checklist in our PR template so that developers don't forget it, but even then there were cases where status bar color would be different. One common case that Status bar background color would be #F7F7F7, and header color would be white. So, normally developers didn't notice something different.
  4. Finally, the current solution that we are using is HOC withStatusBar(). And while exporting a screen for react navigation navigator, we wrap screen with this HOC. Some sample uses.
    withStatusBar()(connect(mapStateToProps)(About))
    ...
    withStatusBar({color: headerColor})(connect(mapStateToProps)(About))

    Inside this HOC, we are using didFocus events, and not isFocused prop. It works for all our cases.

For this RFC, Nice thing about defining status bar in navigation options is that we can define a default status bar color that works for most of screens in top level navigator, and then whichever screen/route needs a new status bar color, that can also be customized using navigation options of that screen. One thing that we need to ensure with navigation options is that on every route change we should set status bar color by picking it up from screen's navigation options or default options because one screen can change status bar color to white, and previous route might need red color when we goBack() or we need to set default color again.

There is one use case in my mind that can't be handled with static navigation options. If a screen needs to change status bar color dynamically, then there is no way to set dynamic color and re-render/set status bar color and style. Example of dynamic status bar color is that same screen/route is used to render different friends's profile, and developer might want to choose a color from image or some screen is used to show info for different fruits and developer might want to match status bar with fruit color. It might be that there is a way to change dynamic status bar color from static navigation options and I don't know about it. Our solution #1 handles this scenario, but our HOC can't handle this scenario. HOC in general can't handle this scenario unless developers lift the status bar color state to a prop that can trigger a re-render to HOC and change status bar color, which, I am not sure if all developers would like to do.

In my opinion, React hooks can handle dynamic status bar and attaching to events like didFocus without component re-rendering. But, one problem that hooks and HOC share is that we have to import it in every screen of an app and then call them. With navigation options, defining defaults is pretty easy and only for those screens that needs something different, developers can import a hook useStatusBar exposed by react navigation. Now, we might think that a combination of navigation options with a hook could solve most of the use cases and issues with Status Bar. But, there is one issue that I forsee in combination approach. If we are using both navigation options for default config and a hook inside render method, then we need to ensure that react navigation's Status Bar config options code runs before render method of screen component, because screen component status bar calls takes precedence on navigation options.

If we can ensure the order of execution for setting status bar color and style, then I think a combination of default navigation options along with useStatusBar hook, we should handle almost all cases of handling status bar with react navigation.

If we have a way to handle dynamic status bar with static navigation options, then I think we won't need a React hook and just navigations options should be able to handle most use cases.

Once we finalize on rfc, I can work on creating a PR that adds support for it, If no one is already working on it. But this is my first time contributing to react navigation (or any open source project) so it might take more time than others who are familiar with it.

buzybee83 commented 4 years ago

Any update on this?