Skip to content

Commit 2be39cd

Browse files
committed
Update docs for safe area handling
1 parent 7d26abf commit 2be39cd

File tree

2 files changed

+71
-33
lines changed

2 files changed

+71
-33
lines changed

versioned_docs/version-4.x/handling-iphonex.md

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,32 @@ title: Supporting safe areas
44
sidebar_label: Supporting safe areas
55
---
66

7-
By default, React Navigation aids in ensuring your application displays correctly on the iPhone X and other devices with notches and "safe areas". It does so by using `SafeAreaView` inside of UI elements that may interact with the sensor cluster ("the notch") or the home activity indicator.
7+
By default, React Navigation tries to ensure that the elements of the navigators display correctly on devices with notches (e.g. iPhone X) and UI elements which may overlap the app content. Such items include:
88

9-
The goal is to (a) maximize usage of the screen (b) without hiding content or making it difficult to interact with by having it obscured by a physical display cutout or some operating system UI.
9+
- Physical notches
10+
- Status bar overlay
11+
- Home activity indicator on iOS
12+
- Navigation bar on Android
1013

11-
It's tempting to solve (a) by wrapping your entire app in a container with padding that ensures all content will not be occluded. But in doing so, we waste a bunch of space on the screen, as pictured in the image on the left below. What we ideally want is the image pictured on the right. We can use `SafeAreaView` for this. The rest of this guide gives more information on how to support safe areas in React Navigation.
14+
The area not overlapped by such items is referred to as "safe area".
1215

13-
![](/assets/iphoneX/00-intro.png)
16+
We try to apply proper insets on the UI elements of the navigators to avoid being overlapped by such items. The goal is to (a) maximize usage of the screen (b) without hiding content or making it difficult to interact with by having it obscured by a physical display cutout or some operating system UI.
1417

15-
<a href="https://snack.expo.io/@react-navigation/boring-safe-area" target="blank" class="run-code-button">&rarr; Run the example pictured on the left</a> or, preferably, <a href="https://snack.expo.io/@react-navigation/nice-safe-area" target="blank" class="run-code-button">run the example pictured on the right.</a>
18+
While React Navigation handles safe areas for the built-in UI elements by default, your own content also needs to handle it to ensure that content isn't hidden by these items.
19+
20+
It's tempting to solve (a) by wrapping your entire app in a container with padding that ensures all content will not be occluded. But in doing so, we waste a bunch of space on the screen, as pictured in the image on the left below. What we ideally want is the image pictured on the right.
21+
22+
![Notch on the iPhone X](/assets/iphoneX/00-intro.png)
23+
24+
While React Native exports a `SafeAreaView` component, it has some inherent issues, i.e. if a screen containing safe area is animating, it causes jumpy behavior. In addition, this component only supports iOS 10+ with no support for older iOS versions or Android. We recommend to use the [react-native-safe-area-context](https://github.com/th3rdwave/react-native-safe-area-context) library to handle safe areas in a more reliable way.
25+
26+
The rest of this guide gives more information on how to support safe areas in React Navigation.
1627

1728
## Hidden/Custom Navigation Bar or Tab Bar
1829

1930
![Default React Navigation Behavior](/assets/iphoneX/01-iphonex-default.png)
2031

21-
However, if you're overriding the default navigation bar, it's important to ensure your UI doesn't interfere with either of those hardware elements.
32+
React Navigation handles safe area in the default header. However, if you're using a custom header, it's important to ensure your UI is within the safe area.
2233

2334
For example, if I render nothing for the `header` or `tabBarComponent`, nothing renders
2435

@@ -38,7 +49,7 @@ export default createStackNavigator({
3849

3950
![Text hidden by iPhoneX UI elements](/assets/iphoneX/02-iphonex-content-hidden.png)
4051

41-
To fix this issue you can wrap your content in a `SafeAreaView`, which can be imported from `react-navigation`. Recall that `SafeAreaView` should not wrap entire navigators, just the screen components or any content in them.
52+
To fix this issue you can apply safe area insets on your content. This can be achieved easily by using the `SafeAreaView` component from the `react-native-safe-area-context` library. Recall that `SafeAreaView` should not wrap entire navigators, just the content inside the screen.
4253

4354
```jsx
4455
import SafeAreaView from 'react-native-safe-area-view';
@@ -55,6 +66,8 @@ class MyHomeScreen extends Component {
5566
}
5667
```
5768

69+
Make sure to wrap your app in `SafeAreaProvider` as per the instructions [here](https://github.com/th3rdwave/react-native-safe-area-context#usage).
70+
5871
![Content spaced correctly with SafeAreaView](/assets/iphoneX/03-iphonex-content-fixed.png)
5972

6073
This will detect if the app is running on an iPhoneX and, if so, ensure the content isn't hidden behind any hardware elements.
@@ -71,42 +84,52 @@ To fix this you can, once again, wrap your content in a `SafeAreaView`. This wil
7184

7285
In conclusion, use the `SafeAreaView` component on the screens you register with a React Navigation navigator.
7386

74-
A [Snack](https://snack.expo.io/@react-navigation/docs:-iphonex-demo-v3) is available with the code used in this overview.
75-
76-
## Use `forceInset` to get more control
87+
## Use the `edges` prop to customize the safe area
7788

78-
In some cases you might need more control over which paddings are applied. For example, you can remove bottom padding by passing `forceInset` prop to `SafeAreaView`.
89+
In some cases you might need more control over which paddings are applied. For example, you can remove bottom padding by passing `edges` prop to `SafeAreaView`.
7990

8091
```jsx
81-
<SafeAreaView style={styles.container} forceInset={{ bottom: 'never' }}>
92+
<SafeAreaView style={styles.container} edges={['top', 'left', 'right']}>
8293
<Text style={styles.paragraph}>This is top text.</Text>
8394
<Text style={styles.paragraph}>This is bottom text.</Text>
8495
</SafeAreaView>
8596
```
8697

87-
`forceInset` takes an object with the keys `top | bottom | left | right | vertical | horizontal` and the values `'always' | 'never'`. Or you can override the padding altogether by passing an integer.
88-
89-
There is also a [Snack](https://snack.expo.io/@react-navigation/react-navigation-docs:-safeareaview-demo-v3) available to demonstrate how `forceInset` behaves.
98+
`edges` takes an array with the values `top`, `bottom`, `left` and `right` which controls which sides the safe area are applied to.
9099

91-
## Android notches
100+
## Use the hook for more control
92101

93-
React Native does not currently expose an API to access information about device cutouts on Android devices. If your app has an opaque status bar (the default in React Native), that may handle the area where the device has its cutout without any further work required. If not, to workaround this you may want to use the following temporary workaround:
102+
In some cases you might need more control over which paddings are applied. For example, you can only apply the top and the bottom padding by changing the `style` object:
94103

95-
- Install [react-native-device-info](https://github.com/react-native-community/react-native-device-info).
96-
- Check if the device has a notch with `DeviceInfo.hasNotch()` - this compares the device brand and model to a list of devices with notches - a crude but effective workaround.
97-
- If the device has a notch, you may want to increase the status bar height known to the SafeAreaView by doing something like this:
98-
99-
```js
100-
import { Platform } from 'react-native';
101-
import SafeAreaView from 'react-native-safe-area-view';
102-
import DeviceInfo from 'react-native-device-info';
103-
104-
if (Platform.OS === 'android' && DeviceInfo.hasNotch()) {
105-
SafeAreaView
106-
.setStatusBarHeight
107-
/* Some value for status bar height + notch height */
108-
();
104+
```jsx
105+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
106+
107+
function Demo() {
108+
const insets = useSafeAreaInsets();
109+
110+
return (
111+
<View
112+
style={{
113+
paddingTop: insets.top,
114+
paddingBottom: insets.bottom,
115+
116+
flex: 1,
117+
justifyContent: 'space-between',
118+
alignItems: 'center',
119+
}}
120+
>
121+
<Text>This is top text.</Text>
122+
<Text>This is bottom text.</Text>
123+
</View>
124+
);
109125
}
110126
```
111127

112-
Work is in progress on a longer term solution, see [this pull request](https://github.com/facebook/react-native/pull/20999) for more information.
128+
Similarly, you could apply these paddings in `contentContainerStyle` of `FlatList` to have the content avoid the safe areas, but still show them under the statusbar and navigation bar when scrolling.
129+
130+
## Summary
131+
132+
- Use `react-native-safe-area-context` instead of `SafeAreaView` from `react-native`
133+
- Don't wrap your whole app in `SafeAreaView`, instead wrap content inside your screens
134+
- Use the `edges` prop to apply safe are to specific sides
135+
- Use the `useSafeAreaInsets` hook for more control over where the insets are applied

versioned_docs/version-6.x/handling-safe-area.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,19 @@ To fix this you can, once again, apply safe area insets to your content. This wi
124124

125125
![App in landscape mode with text visible](/assets/iphoneX/05-iphonex-landscape-fixed.png)
126126

127+
## Use the `edges` prop to customize the safe area
128+
129+
In some cases you might need more control over which paddings are applied. For example, you can remove bottom padding by passing `edges` prop to `SafeAreaView`.
130+
131+
```jsx
132+
<SafeAreaView style={styles.container} edges={['top', 'left', 'right']}>
133+
<Text style={styles.paragraph}>This is top text.</Text>
134+
<Text style={styles.paragraph}>This is bottom text.</Text>
135+
</SafeAreaView>
136+
```
137+
138+
`edges` takes an array with the values `top`, `bottom`, `left` and `right` which controls which sides the safe area are applied to.
139+
127140
## Use the hook for more control
128141

129142
In some cases you might need more control over which paddings are applied. For example, you can only apply the top and the bottom padding by changing the `style` object:
@@ -158,5 +171,7 @@ Similarly, you could apply these paddings in `contentContainerStyle` of `FlatLis
158171

159172
## Summary
160173

174+
- Use `react-native-safe-area-context` instead of `SafeAreaView` from `react-native`
161175
- Don't wrap your whole app in `SafeAreaView`, instead wrap content inside your screens
162-
- Use `useSafeAreaInsets` hook for more control over where the insets are applied
176+
- Use the `edges` prop to apply safe are to specific sides
177+
- Use the `useSafeAreaInsets` hook for more control over where the insets are applied

0 commit comments

Comments
 (0)