Skip to content

Commit 185289a

Browse files
davepackspencercarli
authored andcommitted
Add iPhone X SafeAreaView (react-navigation#2833)
* Add SafeAreaView - JS only version * Add SafeAreaView * Looking pretty good * Small refactor * Remove console.log * Fix merge conflict with Header flow types. * Fix conflict with itemsContainerStyle. * Fix merge conflict. * Fix merge conflict, yarn and package.json from fixflow * Fix merge conflict, navigation playground yarn.lock and package.json with fixflow * Now it can work on lower versions of RN * Snapshots merge conflict. * Update DrawerNavigator snapshot. * Fix conflict with iconContainerStyle * Add support for correct status bar height on iPad. * Update jest snapshots. * Update StackNavigator snapshot. * Use modulo instead of while * Fix landscape tab bar width on < iOS 11
1 parent d1c434b commit 185289a

23 files changed

+1002
-647
lines changed

examples/NavigationPlayground/js/App.js

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
Text,
1414
View,
1515
} from 'react-native';
16-
import { StackNavigator } from 'react-navigation';
16+
import { SafeAreaView, StackNavigator } from 'react-navigation';
1717

1818
import Banner from './Banner';
1919
import CustomTabs from './CustomTabs';
@@ -58,12 +58,14 @@ const ExampleRoutes = {
5858
screen: CustomTransitioner,
5959
},
6060
ModalStack: {
61-
name: Platform.OS === 'ios'
62-
? 'Modal Stack Example'
63-
: 'Stack with Dynamic Header',
64-
description: Platform.OS === 'ios'
65-
? 'Stack navigation with modals'
66-
: 'Dynamically showing and hiding the header',
61+
name:
62+
Platform.OS === 'ios'
63+
? 'Modal Stack Example'
64+
: 'Stack with Dynamic Header',
65+
description:
66+
Platform.OS === 'ios'
67+
? 'Stack navigation with modals'
68+
: 'Dynamically showing and hiding the header',
6769
screen: ModalStack,
6870
},
6971
StacksInTabs: {
@@ -91,7 +93,7 @@ const ExampleRoutes = {
9193
};
9294

9395
const MainScreen = ({ navigation }) => (
94-
<ScrollView>
96+
<ScrollView style={{ flex: 1 }} contentInsetAdjustmentBehavior="automatic">
9597
<Banner />
9698
{Object.keys(ExampleRoutes).map((routeName: string) => (
9799
<TouchableOpacity
@@ -103,12 +105,17 @@ const MainScreen = ({ navigation }) => (
103105
navigation.navigate(routeName, {}, action);
104106
}}
105107
>
106-
<View style={styles.item}>
107-
<Text style={styles.title}>{ExampleRoutes[routeName].name}</Text>
108-
<Text style={styles.description}>
109-
{ExampleRoutes[routeName].description}
110-
</Text>
111-
</View>
108+
<SafeAreaView
109+
style={styles.itemContainer}
110+
forceInset={{ vertical: 'never' }}
111+
>
112+
<View style={styles.item}>
113+
<Text style={styles.title}>{ExampleRoutes[routeName].name}</Text>
114+
<Text style={styles.description}>
115+
{ExampleRoutes[routeName].description}
116+
</Text>
117+
</View>
118+
</SafeAreaView>
112119
</TouchableOpacity>
113120
))}
114121
</ScrollView>
@@ -137,9 +144,11 @@ export default () => <AppNavigator />;
137144

138145
const styles = StyleSheet.create({
139146
item: {
140-
backgroundColor: '#fff',
141147
paddingHorizontal: 16,
142148
paddingVertical: 12,
149+
},
150+
itemContainer: {
151+
backgroundColor: '#fff',
143152
borderBottomWidth: StyleSheet.hairlineWidth,
144153
borderBottomColor: '#ddd',
145154
},

examples/NavigationPlayground/js/Banner.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,30 @@
33
import React from 'react';
44

55
import { Image, Platform, StyleSheet, Text, View } from 'react-native';
6+
import { SafeAreaView } from 'react-navigation';
67

78
const Banner = () => (
8-
<View style={styles.banner}>
9-
<Image source={require('./assets/NavLogo.png')} style={styles.image} />
10-
<Text style={styles.title}>React Navigation Examples</Text>
11-
</View>
9+
<SafeAreaView
10+
style={styles.bannerContainer}
11+
forceInset={{ vertical: 'never' }}
12+
>
13+
<View style={styles.banner}>
14+
<Image source={require('./assets/NavLogo.png')} style={styles.image} />
15+
<Text style={styles.title}>React Navigation Examples</Text>
16+
</View>
17+
</SafeAreaView>
1218
);
1319

1420
export default Banner;
1521

1622
const styles = StyleSheet.create({
17-
banner: {
23+
bannerContainer: {
1824
backgroundColor: '#673ab7',
25+
},
26+
banner: {
1927
flexDirection: 'row',
2028
alignItems: 'center',
2129
padding: 16,
22-
marginTop: Platform.OS === 'ios' ? 20 : 0,
2330
},
2431
image: {
2532
width: 36,

examples/NavigationPlayground/js/CustomTabs.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,23 @@ import {
1515
import {
1616
createNavigator,
1717
createNavigationContainer,
18+
SafeAreaView,
1819
TabRouter,
1920
addNavigationHelpers,
2021
} from 'react-navigation';
2122
import SampleText from './SampleText';
2223

2324
const MyNavScreen = ({ navigation, banner }) => (
2425
<ScrollView>
25-
<SampleText>{banner}</SampleText>
26-
<Button
27-
onPress={() => {
28-
navigation.goBack(null);
29-
}}
30-
title="Go back"
31-
/>
26+
<SafeAreaView forceInset={{ horizontal: 'always' }}>
27+
<SampleText>{banner}</SampleText>
28+
<Button
29+
onPress={() => {
30+
navigation.goBack(null);
31+
}}
32+
title="Go back"
33+
/>
34+
</SafeAreaView>
3235
</ScrollView>
3336
);
3437

@@ -47,7 +50,7 @@ const MySettingsScreen = ({ navigation }) => (
4750
const CustomTabBar = ({ navigation }) => {
4851
const { routes } = navigation.state;
4952
return (
50-
<View style={styles.tabContainer}>
53+
<SafeAreaView style={styles.tabContainer}>
5154
{routes.map(route => (
5255
<TouchableOpacity
5356
onPress={() => navigation.navigate(route.routeName)}
@@ -57,23 +60,23 @@ const CustomTabBar = ({ navigation }) => {
5760
<Text>{route.routeName}</Text>
5861
</TouchableOpacity>
5962
))}
60-
</View>
63+
</SafeAreaView>
6164
);
6265
};
6366

6467
const CustomTabView = ({ router, navigation }) => {
6568
const { routes, index } = navigation.state;
6669
const ActiveScreen = router.getComponentForRouteName(routes[index].routeName);
6770
return (
68-
<View style={styles.container}>
71+
<SafeAreaView forceInset={{ top: 'always' }}>
6972
<CustomTabBar navigation={navigation} />
7073
<ActiveScreen
7174
navigation={addNavigationHelpers({
7275
dispatch: navigation.dispatch,
7376
state: routes[index],
7477
})}
7578
/>
76-
</View>
79+
</SafeAreaView>
7780
);
7881
};
7982

@@ -103,9 +106,6 @@ const CustomTabs = createNavigationContainer(
103106
);
104107

105108
const styles = StyleSheet.create({
106-
container: {
107-
marginTop: Platform.OS === 'ios' ? 20 : 0,
108-
},
109109
tabContainer: {
110110
flexDirection: 'row',
111111
height: 48,

examples/NavigationPlayground/js/CustomTransitioner.js

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,27 @@ import {
1010
} from 'react-native';
1111
import {
1212
Transitioner,
13+
SafeAreaView,
1314
StackRouter,
1415
createNavigationContainer,
1516
addNavigationHelpers,
16-
createNavigator
17+
createNavigator,
1718
} from 'react-navigation';
1819
import SampleText from './SampleText';
1920

2021
const MyNavScreen = ({ navigation, banner }) => (
21-
<View>
22+
<SafeAreaView forceInset={{ top: 'always' }}>
2223
<SampleText>{banner}</SampleText>
23-
{navigation.state && navigation.state.routeName !== 'Settings' &&
24-
<Button
25-
onPress={() => navigation.navigate('Settings')}
26-
title="Go to a settings screen"
27-
/>
28-
}
29-
30-
<Button
31-
onPress={() => navigation.goBack(null)}
32-
title="Go back"
33-
/>
34-
</View>
24+
{navigation.state &&
25+
navigation.state.routeName !== 'Settings' && (
26+
<Button
27+
onPress={() => navigation.navigate('Settings')}
28+
title="Go to a settings screen"
29+
/>
30+
)}
31+
32+
<Button onPress={() => navigation.goBack(null)} title="Go back" />
33+
</SafeAreaView>
3534
);
3635

3736
const MyHomeScreen = ({ navigation }) => (
@@ -63,13 +62,11 @@ class CustomNavigationView extends Component {
6362
}
6463

6564
_render = (transitionProps, prevTransitionProps) => {
66-
const scenes = transitionProps.scenes.map(scene => this._renderScene(transitionProps, scene));
67-
return (
68-
<View style={{ flex: 1 }}>
69-
{scenes}
70-
</View>
65+
const scenes = transitionProps.scenes.map(scene =>
66+
this._renderScene(transitionProps, scene)
7167
);
72-
}
68+
return <View style={{ flex: 1 }}>{scenes}</View>;
69+
};
7370

7471
_renderScene = (transitionProps, scene) => {
7572
const { navigation, router } = this.props;
@@ -84,9 +81,7 @@ class CustomNavigationView extends Component {
8481

8582
const animation = {
8683
opacity: animatedValue,
87-
transform: [
88-
{ scale: animatedValue },
89-
],
84+
transform: [{ scale: animatedValue }],
9085
};
9186

9287
// The prop `router` is populated when we call `createNavigator`.
@@ -100,8 +95,8 @@ class CustomNavigationView extends Component {
10095
})}
10196
/>
10297
</Animated.View>
103-
)
104-
}
98+
);
99+
};
105100
}
106101

107102
const CustomRouter = StackRouter({
@@ -116,9 +111,6 @@ const CustomTransitioner = createNavigationContainer(
116111
export default CustomTransitioner;
117112

118113
const styles = StyleSheet.create({
119-
container: {
120-
marginTop: Platform.OS === 'ios' ? 20 : 0,
121-
},
122114
view: {
123115
position: 'absolute',
124116
left: 0,

examples/NavigationPlayground/js/Drawer.js

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@
33
*/
44

55
import React from 'react';
6-
import { Button, Platform, ScrollView, StyleSheet } from 'react-native';
7-
import { DrawerNavigator } from 'react-navigation';
6+
import { Button, Platform, ScrollView } from 'react-native';
7+
import { DrawerNavigator, SafeAreaView } from 'react-navigation';
88
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
99
import SampleText from './SampleText';
1010

1111
const MyNavScreen = ({ navigation, banner }) => (
12-
<ScrollView style={styles.container}>
13-
<SampleText>{banner}</SampleText>
14-
<Button
15-
onPress={() => navigation.navigate('DrawerOpen')}
16-
title="Open drawer"
17-
/>
18-
<Button onPress={() => navigation.goBack(null)} title="Go back" />
12+
<ScrollView>
13+
<SafeAreaView forceInset={{ top: 'always' }}>
14+
<SampleText>{banner}</SampleText>
15+
<Button
16+
onPress={() => navigation.navigate('DrawerOpen')}
17+
title="Open drawer"
18+
/>
19+
<Button onPress={() => navigation.goBack(null)} title="Go back" />
20+
</SafeAreaView>
1921
</ScrollView>
2022
);
2123

@@ -62,10 +64,4 @@ const DrawerExample = DrawerNavigator(
6264
}
6365
);
6466

65-
const styles = StyleSheet.create({
66-
container: {
67-
marginTop: Platform.OS === 'ios' ? 20 : 0,
68-
},
69-
});
70-
7167
export default DrawerExample;

examples/NavigationPlayground/js/ModalStack.js

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,38 @@
44

55
import React from 'react';
66
import { Button, ScrollView, Text } from 'react-native';
7-
import { StackNavigator } from 'react-navigation';
7+
import { SafeAreaView, StackNavigator } from 'react-navigation';
88
import SampleText from './SampleText';
99

1010
const MyNavScreen = ({ navigation, banner }) => (
11-
<ScrollView>
12-
<SampleText>{banner}</SampleText>
13-
<Button
14-
onPress={() => navigation.navigate('Profile', { name: 'Jane' })}
15-
title="Go to a profile screen"
16-
/>
17-
<Button
18-
onPress={() => navigation.navigate('HeaderTest')}
19-
title="Go to a header toggle screen"
20-
/>
21-
{navigation.state.routeName === 'HeaderTest' &&
11+
<ScrollView contentInsetAdjustmentBehavior="automatic">
12+
<SafeAreaView
13+
forceInset={{
14+
top: navigation.state.routeName === 'HeaderTest' ? 'always' : 'never',
15+
}}
16+
>
17+
<SampleText>{banner}</SampleText>
2218
<Button
23-
title="Toggle Header"
24-
onPress={() =>
25-
navigation.setParams({
26-
headerVisible: !navigation.state.params ||
27-
!navigation.state.params.headerVisible,
28-
})}
29-
/>}
30-
<Button onPress={() => navigation.goBack(null)} title="Go back" />
19+
onPress={() => navigation.navigate('Profile', { name: 'Jane' })}
20+
title="Go to a profile screen"
21+
/>
22+
<Button
23+
onPress={() => navigation.navigate('HeaderTest')}
24+
title="Go to a header toggle screen"
25+
/>
26+
{navigation.state.routeName === 'HeaderTest' && (
27+
<Button
28+
title="Toggle Header"
29+
onPress={() =>
30+
navigation.setParams({
31+
headerVisible:
32+
!navigation.state.params ||
33+
!navigation.state.params.headerVisible,
34+
})}
35+
/>
36+
)}
37+
<Button onPress={() => navigation.goBack(null)} title="Go back" />
38+
</SafeAreaView>
3139
</ScrollView>
3240
);
3341

0 commit comments

Comments
 (0)