Skip to content

Commit

Permalink
[expo-status-bar] Simple new module that wraps React Native StatusBar (
Browse files Browse the repository at this point in the history
…#8624)

* First pass at a simple wrapper around StatusBar to make it work more nicely for Expo users

* Run expo-module configure

* Commit build files

* Update exports

* Add expo-status-bar docs page

* Fix expo-apple-authentication props link

* Use useColorScheme instead of Appearance.getColorScheme in order to update automatically when scheme changes

* Use expo-constants to pick the correct translucent config

* Add warning if incompatible version of Expo / React Native is being used

* Update the configuring-statusbar docs page and remove warning for now

* Better handling on Android of various common cases

* Update the title for the guides section

* Fix lint error

* Apply default style always when component is mounted

* Rewrite a bunch of expo-status-bar

* Properly pass through the translucent prop

* Use expo-status-bar and support themes in tabs template

* Update tests

* Update docs

* More tests and docs updates

* Update CHANGELOG

* Add missing build files
  • Loading branch information
brentvatne committed Jun 13, 2020
1 parent 75fbf44 commit 8fa0b00
Show file tree
Hide file tree
Showing 82 changed files with 1,326 additions and 366 deletions.
2 changes: 1 addition & 1 deletion docs/common/navigation.js
Expand Up @@ -57,7 +57,7 @@ const sections = [
'Authentication',
'App Icons',
'Create a Splash Screen',
'Configuring StatusBar',
'Configuring the Status Bar',
'Configuring OTA Updates',
'Preloading & Caching Assets',
'Offline Support',
Expand Down
151 changes: 78 additions & 73 deletions docs/pages/guides/configuring-statusbar.md
@@ -1,31 +1,49 @@
---
title: Configuring StatusBar
title: Configuring the Status Bar
---

Expo and React Native provide APIs and configuration options for Android to configure the status bar for your app. These can be used to control the appearance of the status bar in your app.
The status bar configuration often feels like a small detail to a developer, but it can make a big difference on the overall feel and perceived level of polish of your app by users. When you have a white status bar on a white background, you just know something isn't going quite right.

## Configuration (Android)
This guide is intended to help you know what tools are at your disposal to configure the status bar for your iOS and Android apps.

The configuration for Android status bar lives under the `androidStatusBar` key in `app.json`. It exposes the following options:
<div style={{backgroundColor: '#fafafa', flex: 1, textAlign: 'center'}}>
<img src="/static/images/status-bar-style-comparison.png" alt="A comparison of good and bad status bar styling" />
</div>

### `barStyle`
<br />

> 👀 Notice how bad the contrast is between the status bar text and the background in the second image. This is what we want to try to avoid.
## Configuring the status bar while your app is loading (Android only)

> This type of configuration is currently only available on Android. On iOS, it is not possible in the Expo managed workflow to customize the status bar before the app has loaded, while the splash screen is presented.
The configuration for configuring the status bar while the splash screen is visible on Android is available through the `androidStatusBar` object in `app.json`. The options available are similar to those provided by [expo-status-bar](/versions/latest/sdk/status-bar).

<div style={{marginTop: -10}} />

<details><summary><h4>See the full list of options available to configure the status bar statically on Android.</h4></summary>
<p>

### `androidStatusBar.barStyle`

This option can be used to specify whether the status bar content (icons and text in the status bar) is light, or dark. Usually a status bar with a light background has dark content, and a status bar with a dark background has light content.

The valid values are:
- `light-content` - The status bar content is light colored (usually white).
- `dark-content` - The status bar content is dark colored (usually dark grey). This is only available on Android 6.0 onwards. It will fallback to `light-content` in older versions. This is the default value.

- `light-content` - The status bar content is light colored (usually white). This is equivalent to `expo-status-bar` `style="light"`.
- `dark-content` - The status bar content is dark colored (usually dark grey). This is equivalent to `expo-status-bar` `style="dark"`. This is only available on Android 6.0 onwards. It will fallback to `light-content` in older versions. This is the default value.

> Note: If you choose `light-content` and have either a very light image set as the `SplashScreen` or `backgroundColor` set to a light color, the status bar icons may blend in and not be visible.
> Same goes for `dark-content` when you have a very dark image set as the `SplashScreen` or `backgroundColor` set to a dark color.
### `backgroundColor`
### `androidStatusBar.backgroundColor`

This option can be used to set a background color for the status bar.
The valid value is a 6-character long hexadecimal solid color string with the format `#RRGGBB` (e.g. `#C2185B`) or 8-character long hexadecimal color string with transparency with the format `#RRGGBBAA` (e.g. `#23C1B255`).
Defaults to `#00000000` (fully transparent color) for `dark-content` bar style and `#00000088` (semi-transparent black) for `light-content` bar style.

### `translucent`
### `androidStatusBar.translucent`

Value type - `boolean`.
Specifies whether the status bar should be translucent.
Expand All @@ -36,19 +54,64 @@ Defaults to `true`.
> Note: A translucent status bar makes sense when the `backgroundColor` is using a transparent color (`#RRGGBBAA`).
> When you use a translucent status bar and a solid `backgroundColor` (`#RRGGBB`) then the upper part of your app will be partially covered by the non-transparent status bar and thus some of your app's content might not be visible to the user.
### `hidden`
### `androidStatusBar.hidden`

Value type - `boolean`.
Tells the system whether the status bar should be visible or not.
When the status bar is not visible it can be presented via the `swipe down` gesture.
When set to `true`, the status bar will not respect `backgroundColor` or `barStyle` settings.
Defaults to `false`.

## Working with 3rd-party Libraries
</p>
</details>

## Updating the status bar while your app is running

The `StatusBar` component provided by [expo-status-bar](/versions/latest/sdk/status-bar/) allows you to control the appearance of the status bar while your app is running. expo-status-bar also provides imperative methods such as `setStatusBarStyle(style)` to control the style through function calls rather than the `StatusBar` component, if you find that to be helpful for your use case.

To fix the contrast issue from the screenshot at the top of this guide, we could use the following code:

```js
import React from 'react';
import { View } from 'react-native';
import { StatusBar } from 'expo-status-bar';

export default function Playlists() {
return (
<View>
{/* other code here to show the screen */}

{/* use light text instead of dark text in the status bar to provide more contrast with a dark background */}
<StatusBar style="light" />
</View>
);
}
```

<details><summary><h4>How is expo-status-bar different from the StatusBar component included in React Native?</h4></summary>
<p>

`expo-status-bar` builds on top of the `StatusBar` component that React Native provides in order to give you better defaults when you're building an app with Expo tools. For example, the `translucent` property of `expo-status-bar` defaults to `true` or, if you have changed that property in `androidStatusBar`, it will use that value instead. The default in React Native for `translucent` is always `false`, which can be confusing when in projects created using Expo tools, because the default is `true` for consistency with iOS.

</p>
</details>


## Themes and status bar styles

If you use `expo-status-bar` to control your status bar style, the `style="auto"` configuration will automatically pick the appropriate default style depending on the color scheme currently used by the app (this is the default behavior, if you leave out the style prop entirely then `auto` will be used). Please note that if you provide a way for users to toggle between color schemes rather than using the operating system theme, this will not have the intended behavior, and you should use `style="light"` and `style="dark"` as needed depending on the selected color scheme.

> 💡Automatic theme detection is only supported in SDK 38 or higher. Prior to SDK 38, `auto` will not change depending on your color scheme, it will always assume that the theme is light.
## Factoring the status bar in with your layout

Expo makes the status bar `translucent` by default on Android which is consistent with iOS, and more in line with material design. Unfortunately some libraries don't support `translucent` status bars, e.g. - navigation libraries, libraries which provide a header bar etc.
When you have a translucent status bar, it's important to remember that content can be rendered underneath it (if it couldn't, what would be the point of it being translucent? there would be nothing for you to see through it!).

If you need to use such a library, there are a few options:
Libraries like [React Navigation](../../guides/routing-and-navigation/) will handle this for you when the UI that they provide overlap with the status bar. You are likely to encounter cases where you will need to manually adjust your layout to prevent some content (such as text) from being rendered underneath it. To do this, we recommend using [react-native-safe-area-context](/versions/latest/sdk/safe-area-context/) to find the safe area insets and add padding or margins to your layout accordingly.

## Working with misbehaving 3rd-party Libraries

Projects initialized with Expo tools make the status bar `translucent` by default on Android. This is consistent with iOS and more in line with material design. Unfortunately, some libraries don't support `translucent` status bars. This is generally bad practice and those libraries should be fixed, but if you must use one of them, there are some options available for you to accommodate their limitations:

### Set the `backgroundColor` of the status bar to an opaque color and disable `translucent` option

Expand All @@ -57,6 +120,7 @@ You need to explicitly set `translucent` to `false` if you want your app's statu
This is a good option if your status bar color never needs to change.

Example:

```json
{
"expo": {
Expand All @@ -68,65 +132,6 @@ Example:
}
```

### Use the [`StatusBar` API from React Native](https://reactnative.dev/docs/statusbar.html)

The `StatusBar` API allows you to dynamically control the appearance of the status bar. You can use it as component, or as an API. Check the documentation on the React Native website for examples.

### Place an empty `View` on top of your screen

You can place an empty `View` on top of your screen with a background color to act as a status bar, or set a top padding. You can get the height of the status bar with `Constants.statusBarHeight`. Though this should be your last resort since this doesn't work very well when status bar's height changes.

Example:
```js
import React from 'react';
import { StyleSheet, View } from 'react-native';
import Constants from 'expo-constants';

const styles = StyleSheet.create({
statusBar: {
backgroundColor: "#C2185B",
height: Constants.statusBarHeight,
},

// rest of the styles
});

const MyComponent = () => {
<View>
<View style={styles.statusBar} />
{/* rest of the content */}
</View>
}
```

If you don't need to set the background color, you can just set a top padding on the wrapping `View` instead.

## Recommended configuration

It is recommended to use the configuration in `app.json` to obtain the appearance you want to have during the `SplashScreen` phase, and later on use the [`StatusBar` API from React Native](https://reactnative.dev/docs/statusbar.html) to dynamically adjust status bar appearance.

Example:
```ts
// App.json

{
...
"androidStatusBar": {
"hidden": false, // default value
"translucent": true, // default value to align with default iOS behavior
"barStyle": "dark-content", // default value
"backgroundColor": "#00000000" // default value depends on "barStyle" value - fully-transparent when it is `dark-content` and semi-transparent black for `light-content`
},
...
}
```
```tsx
// Root Component

import { StatusBar } from 'react-native';

...

StatusBar.setBarStyle('dark-content');
StatusBar.setBackgroundColor('#123456');
```
You can place an empty `View` on top of your screen with a background color to act as a status bar, or set a top padding. You can get the height of the status bar (and notch, if there is one) by using the top inset value provided by [react-native-safe-area-context](/versions/latest/sdk/safe-area-context/).
Expand Up @@ -87,7 +87,7 @@ import * as AppleAuthentication from 'expo-apple-authentication';

- [`AppleAuthentication.AppleAuthenticationButton`](#appleauthenticationappleauthenticationbutton)

**[Prop Types](#prop-types)**
**[Prop Types](#appleauthenticationappleauthenticationbuttonprops)**

- [`AppleAuthentication.AppleAuthenticationButtonProps`](#appleauthenticationappleauthenticationbuttonprops)

Expand Down
148 changes: 148 additions & 0 deletions docs/pages/versions/unversioned/sdk/status-bar.md
@@ -0,0 +1,148 @@
---
id: statusbar
title: StatusBar
sourceCodeUrl: 'https://github.com/expo/expo/tree/sdk-37/packages/expo-status-bar'
---

import InstallSection from '~/components/plugins/InstallSection';
import PlatformsSection from '~/components/plugins/PlatformsSection';
import SnackInline from '~/components/plugins/SnackInline';

**`expo-status-bar`** gives you a component and imperative interface to control the app status bar to change its text color, background color, hide it, make it translucent or opaque, and apply animations to any of these changes. Exactly what you are able to do with the `StatusBar` component depends on the platform you're using.

<PlatformsSection android emulator ios simulator web />

> **Web browser support**: there is no API available on the web for controlling the operating system status bar, so `expo-status-bar` will noop (it will do nothing, it will also not error).
## Installation

<InstallSection packageName="expo-status-bar" />

## Example Usage

<SnackInline dependencies={["expo-status-bar"]}>

```js
import React from 'react';
import { Text, View } from 'react-native';
import { StatusBar } from 'expo-status-bar';

export default class App extends React.Component {
render() {
return (
<View
style={{
flex: 1,
backgroundColor: '#000',
alignItems: 'center',
justifyContent: 'center',
}}>
<Text style={{ color: '#fff' }}>Notice that the status bar has light text!</Text>
<StatusBar style="light" />
</View>
);
}
}
```

</SnackInline>

## API

```js
import { StatusBar } from 'expo-status-bar';
```

**[Components](#components)**

- [`StatusBar`](#statusbar)

**[Methods](#methods)**

- [`setStatusBarBackgroundColor(backgroundColor, animated)`](#setstatusbarbackgroundcolorbackgroundcolor-animated)
- [`setStatusBarHidden(hidden, animation)`](#setstatusbarhiddenhidden-animation)
- [`setStatusBarNetworkActivityIndicatorVisible(visible)`](#setstatusbarnetworkactivityindicatorvisiblevisible)
- [`setStatusBarStyle(style)`](#setstatusbarstylestyle)
- [`setStatusBarTranslucent(translucent)`](#setstatusbartranslucenttranslucent)

**[Types](#types)**

- [`StatusBarAnimation`](#statusbaranimation)
- [`StatusBarProps`](#statusbarprops)
- [`StatusBarStyle`](#statusbarstyle)

## Components

### `StatusBar`

A component that allows you to configure your status bar without directly calling imperative methods like `setBarStyle`.

You will likely have multiple `StatusBar` components mounted in the same app at the same time. For example, if you have multiple screens in your app, you may end up using one per screen. The props of each `StatusBar` component will be merged in the order that they were mounted. This component is built on top of the [StatusBar](https://reactnative.dev/docs/statusbar) component exported from React Native, and it provides defaults that work better for Expo users.

#### Props

- **style (_[StatusBarStyle](#statusbarstyle)_)** - The color of the status bar text.
- **animated (_boolean_)** - If the transition between status bar property changes, such as `style`, should be animated.
- **hidden (_boolean_)** - If the status bar should be hidden.
- **networkActivityIndicatorVisible (_boolean_)** - If the network activity indicator should be visible. _[iOS only]_
- **hideTransitionAnimation (_[StatusBarAnimation](#statusbaranimation)_)** - The transition effect when showing and hiding the status bar. Defaults to `'fade'`. _[iOS only]_
- **backgroundColor (_string_)** - The background color of the status bar. _[Android only]_
- **translucent (_boolean_)** - Whether the app can draw under the status bar. When `true`, content will be rendered under the status bar. This is always `true` on iOS and cannot be changed. On Android, the default is also `true` unless you have explicitly configured the `androidStatusBar.translucent` key in `app.json` to `false`. _[Android only]_

## Methods

### `setStatusBarBackgroundColor(backgroundColor, animated)`

Set the background color of the status bar. _[Android only]_

#### Arguments

- **backgroundColor (_string_)** - The background color of the status bar.
- **animated (_boolean_)** - `true` to animate the background color change, `false` to change immediately.

### `setStatusBarHidden(hidden, animation)`

Toggle visibility of the status bar.

#### Arguments

- **hidden (_boolean_)** - If the status bar should be hidden.
- **animation (_[StatusBarAnimation](#statusbaranimation)_)** - Animation to use when toggling hidden, defaults to `'none'`.

### `setStatusBarNetworkActivityIndicatorVisible(visible)`

Toggle visibility of the network activity indicator. _[iOS only]_

#### Arguments

- **visible (_boolean_)** - If the network activity indicator should be visible.

### `setStatusBarStyle(style)`

Set the bar style of the status bar.

#### Arguments

- **style (_[StatusBarStyle](#statusbarstyle)_)** - The color of the status bar text.

### `setStatusBarTranslucent(translucent)`

Set the translucency of the status bar. _[Android only]_

#### Arguments

- **translucent (_boolean_)** - Whether the app can draw under the status bar. When `true`, content will be rendered under the status bar. This is always `true` on iOS and cannot be changed.

## Types

### `StatusBarAnimation`

A string, either: `'none'`, `'fade'`, or `'slide'`.

### `StatusBarProps`

See the props of the [StatusBar](#statusbar) component.

### `StatusBarStyle`

A string, either: `'auto'`, `'inverted'`, `'light'`, or `'dark'`.

0 comments on commit 8fa0b00

Please sign in to comment.