Skip to content

Commit 5644527

Browse files
committed
Explicitly recommend not using the SafeAreaView component
1 parent 824a372 commit 5644527

File tree

5 files changed

+199
-64
lines changed

5 files changed

+199
-64
lines changed

static/examples/6.x/safe-area-example.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
11
import * as React from 'react';
2-
import { Text } from 'react-native';
2+
import { View, Text } from 'react-native';
33
import { NavigationContainer } from '@react-navigation/native';
44
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
55
import { createNativeStackNavigator } from '@react-navigation/native-stack';
6-
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
6+
import {
7+
SafeAreaProvider,
8+
useSafeAreaInsets,
9+
} from 'react-native-safe-area-context';
710

811
function Demo() {
12+
const insets = useSafeAreaInsets();
13+
914
return (
10-
<SafeAreaView
11-
style={{ flex: 1, justifyContent: 'space-between', alignItems: 'center' }}
15+
<View
16+
style={{
17+
flex: 1,
18+
justifyContent: 'space-between',
19+
alignItems: 'center',
20+
paddingTop: insets.top,
21+
paddingBottom: insets.bottom,
22+
paddingLeft: insets.left,
23+
paddingRight: insets.right,
24+
}}
1225
>
1326
<Text>This is top text.</Text>
1427
<Text>This is bottom text.</Text>
15-
</SafeAreaView>
28+
</View>
1629
);
1730
}
1831

static/examples/6.x/status-bar-focus-effect.js

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
22
import {
3+
View,
34
Text,
45
StatusBar,
56
Button,
@@ -9,8 +10,10 @@ import {
910
} from 'react-native';
1011
import { NavigationContainer, useIsFocused } from '@react-navigation/native';
1112
import { createDrawerNavigator } from '@react-navigation/drawer';
12-
import { SafeAreaProvider } from 'react-native-safe-area-context';
13-
import SafeAreaView from 'react-native-safe-area-view';
13+
import {
14+
SafeAreaProvider,
15+
useSafeAreaInsets,
16+
} from 'react-native-safe-area-context';
1417

1518
function FocusAwareStatusBar(props) {
1619
const isFocused = useIsFocused();
@@ -19,26 +22,52 @@ function FocusAwareStatusBar(props) {
1922
}
2023

2124
function Screen1({ navigation }) {
25+
const insets = useSafeAreaInsets();
26+
2227
return (
23-
<SafeAreaView style={[styles.container, { backgroundColor: '#6a51ae' }]}>
28+
<View
29+
style={[
30+
styles.container,
31+
{
32+
backgroundColor: '#6a51ae',
33+
paddingTop: insets.top,
34+
paddingBottom: insets.bottom,
35+
paddingLeft: insets.left,
36+
paddingRight: insets.right,
37+
},
38+
]}
39+
>
2440
<FocusAwareStatusBar barStyle="light-content" backgroundColor="#6a51ae" />
2541
<Text style={{ color: '#fff' }}>Light Screen</Text>
2642
<Button
2743
title="Toggle Drawer"
2844
onPress={() => navigation.toggleDrawer()}
2945
color="#fff"
3046
/>
31-
</SafeAreaView>
47+
</View>
3248
);
3349
}
3450

3551
function Screen2({ navigation }) {
52+
const insets = useSafeAreaInsets();
53+
3654
return (
37-
<SafeAreaView style={[styles.container, { backgroundColor: '#ecf0f1' }]}>
55+
<View
56+
style={[
57+
styles.container,
58+
{
59+
backgroundColor: '#ecf0f1',
60+
paddingTop: insets.top,
61+
paddingBottom: insets.bottom,
62+
paddingLeft: insets.left,
63+
paddingRight: insets.right,
64+
},
65+
]}
66+
>
3867
<FocusAwareStatusBar barStyle="dark-content" backgroundColor="#ecf0f1" />
3968
<Text>Dark Screen</Text>
4069
<Button title="Toggle Drawer" onPress={() => navigation.toggleDrawer()} />
41-
</SafeAreaView>
70+
</View>
4271
);
4372
}
4473

static/examples/6.x/status-bar.js

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,61 @@
11
import * as React from 'react';
2-
import { Text, StatusBar, Button, StyleSheet } from 'react-native';
2+
import { View, Text, StatusBar, Button, StyleSheet } from 'react-native';
33
import { NavigationContainer } from '@react-navigation/native';
44
import { createNativeStackNavigator } from '@react-navigation/native-stack';
5-
import { SafeAreaProvider } from 'react-native-safe-area-context';
6-
import SafeAreaView from 'react-native-safe-area-view';
5+
import {
6+
SafeAreaProvider,
7+
useSafeAreaInsets,
8+
} from 'react-native-safe-area-context';
79

810
function Screen1({ navigation }) {
11+
const insets = useSafeAreaInsets();
12+
913
return (
10-
<SafeAreaView style={[styles.container, { backgroundColor: '#6a51ae' }]}>
14+
<View
15+
style={[
16+
styles.container,
17+
{
18+
backgroundColor: '#6a51ae',
19+
paddingTop: insets.top,
20+
paddingBottom: insets.bottom,
21+
paddingLeft: insets.left,
22+
paddingRight: insets.right,
23+
},
24+
]}
25+
>
1126
<StatusBar barStyle="light-content" backgroundColor="#6a51ae" />
1227
<Text style={{ color: '#fff' }}>Light Screen</Text>
1328
<Button
1429
title="Next screen"
1530
onPress={() => navigation.navigate('Screen2')}
1631
/>
17-
</SafeAreaView>
32+
</View>
1833
);
1934
}
2035

2136
function Screen2({ navigation }) {
37+
const insets = useSafeAreaInsets();
38+
2239
return (
23-
<SafeAreaView style={[styles.container, { backgroundColor: '#ecf0f1' }]}>
40+
<View
41+
style={[
42+
styles.container,
43+
{
44+
backgroundColor: '#ecf0f1',
45+
paddingTop: insets.top,
46+
paddingBottom: insets.bottom,
47+
paddingLeft: insets.left,
48+
paddingRight: insets.right,
49+
},
50+
]}
51+
>
2452
<StatusBar barStyle="dark-content" backgroundColor="#ecf0f1" />
2553
<Text>Dark Screen</Text>
2654
<Button
2755
title="Next screen"
2856
onPress={() => navigation.navigate('Screen1')}
2957
/>
30-
</SafeAreaView>
58+
</View>
3159
);
3260
}
3361

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

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ The area not overlapped by such items is referred to as "safe area".
1515

1616
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.
1717

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.
18+
While React Navigation handles safe areas for the built-in UI elements by default, your own content may also need to handle it to ensure that content isn't hidden by these items.
1919

2020
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.
2121

2222
![Notch on the iPhone X](/assets/iphoneX/00-intro.png)
2323

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.
24+
While React Native exports a `SafeAreaView` component, this component only supports iOS 10+ with no support for older iOS versions or Android. In addition, it also has some issues, i.e. if a screen containing safe area is animating, it causes jumpy behavior. So we recommend to use the `useSafeAreaInsets` hook from 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+
> Note: The `react-native-safe-area-context` library also exports a `SafeAreaView` component. While it works on Android, it also has the same issues related to jumpy behavior when animating. So we recommend always using the `useSafeAreaInsets` hook instead and avoid using the `SafeAreaView` component.
2527
2628
The rest of this guide gives more information on how to support safe areas in React Navigation.
2729

@@ -58,18 +60,21 @@ const Tab = createBottomTabNavigator();
5860
export default function App() {
5961
return (
6062
<NavigationContainer>
61-
<Stack.Navigator initialRouteName="Home" screenOptions={{ headerShown: false }}>
63+
<Stack.Navigator
64+
initialRouteName="Home"
65+
screenOptions={{ headerShown: false }}
66+
>
6267
<Stack.Screen name="Home">
63-
{() => (
64-
<Tab.Navigator
65-
initialRouteName="Analitics"
66-
tabBar={() => null}
67-
screenOptions={{ headerShown: false }}
68-
>
69-
<Tab.Screen name="Analitics" component={Demo} />
70-
<Tab.Screen name="Profile" component={Demo} />
71-
</Tab.Navigator>
72-
)}
68+
{() => (
69+
<Tab.Navigator
70+
initialRouteName="Analitics"
71+
tabBar={() => null}
72+
screenOptions={{ headerShown: false }}
73+
>
74+
<Tab.Screen name="Analitics" component={Demo} />
75+
<Tab.Screen name="Profile" component={Demo} />
76+
</Tab.Navigator>
77+
)}
7378
</Stack.Screen>
7479

7580
<Stack.Screen name="Settings" component={Demo} />
@@ -81,21 +86,36 @@ export default function App() {
8186

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

84-
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:
89+
To fix this issue you can apply safe area insets on your content. This can be achieved using the `useSafeAreaInsets` hook from the `react-native-safe-area-context` library:
8590

8691
<samp id="safe-area-example" />
8792

8893
```jsx
89-
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
94+
import {
95+
SafeAreaProvider,
96+
useSafeAreaInsets,
97+
} from 'react-native-safe-area-context';
9098

9199
function Demo() {
100+
const insets = useSafeAreaInsets();
101+
92102
return (
93-
<SafeAreaView
94-
style={{ flex: 1, justifyContent: 'space-between', alignItems: 'center' }}
103+
<View
104+
style={{
105+
flex: 1,
106+
justifyContent: 'space-between',
107+
alignItems: 'center',
108+
109+
// Paddings to handle safe area
110+
paddingTop: insets.top,
111+
paddingBottom: insets.bottom,
112+
paddingLeft: insets.left,
113+
paddingRight: insets.right,
114+
}}
95115
>
96116
<Text>This is top text.</Text>
97117
<Text>This is bottom text.</Text>
98-
</SafeAreaView>
118+
</View>
99119
);
100120
}
101121

@@ -124,19 +144,6 @@ To fix this you can, once again, apply safe area insets to your content. This wi
124144

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

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-
140147
## Use the hook for more control
141148

142149
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:
@@ -171,7 +178,6 @@ Similarly, you could apply these paddings in `contentContainerStyle` of `FlatLis
171178

172179
## Summary
173180

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

0 commit comments

Comments
 (0)