mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-02-14 18:37:20 +08:00
Move SafeAreaView out of DrawerNavigatorItems to DrawerSidebar. (#2967)
* Move SafeAreaView out of DrawerNavigatorItems to DrawerSidebar. The SafeAreaView was breaking custom contentContainers in drawers. Fixes #2963. * Fix SafeAreaView in DrawerItems and Drawer contentComponent * Fix flow error and tests. * Update Drawer documentation with SafeAreaView recommendation. Remove one of the examples for `contentComponent`. * Put the View back. * Update snapshot.
This commit is contained in:
@@ -94,21 +94,6 @@ The route configs object is a mapping from route name to a route config, which t
|
||||
- `useNativeAnimations` - Enable native animations. Default is `true`.
|
||||
- `drawerBackgroundColor` - Use the Drawer background for some color. The Default is `white`.
|
||||
|
||||
#### Example:
|
||||
|
||||
Default the `DrawerView` isn't scrollable.
|
||||
To achieve a scrollable `View`, you have to use the `contentComponent` to customize the container,
|
||||
as you can see in the example below.
|
||||
|
||||
```js
|
||||
{
|
||||
drawerWidth: 200,
|
||||
drawerPosition: 'right',
|
||||
contentComponent: props => <ScrollView><DrawerItems {...props} /></ScrollView>,
|
||||
drawerBackgroundColor: 'transparent'
|
||||
}
|
||||
```
|
||||
|
||||
Several options get passed to the underlying router to modify navigation logic:
|
||||
|
||||
- `initialRouteName` - The routeName for the initial route.
|
||||
@@ -118,15 +103,17 @@ Several options get passed to the underlying router to modify navigation logic:
|
||||
|
||||
### Providing a custom `contentComponent`
|
||||
|
||||
You can easily override the default component used by `react-navigation`:
|
||||
The default component for the drawer is scrollable and only contains links for the routes in the RouteConfig. You can easily override the default component to add a header, footer, or other content to the drawer. By default the drawer is scrollable and supports iPhone X safe area. If you customize the content, be sure to wrap the content in a SafeAreaView:
|
||||
|
||||
```js
|
||||
import { DrawerItems } from 'react-navigation';
|
||||
import { DrawerItems, SafeAreaView } from 'react-navigation';
|
||||
|
||||
const CustomDrawerContentComponent = (props) => (
|
||||
<View style={styles.container}>
|
||||
<DrawerItems {...props} />
|
||||
</View>
|
||||
<ScrollView>
|
||||
<SafeAreaView style={styles.container} forceInset={{ top: 'always', horizontal: 'never' }}>
|
||||
<DrawerItems {...props} />
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -145,7 +132,6 @@ const styles = StyleSheet.create({
|
||||
- `inactiveTintColor` - label and icon color of the inactive label
|
||||
- `inactiveBackgroundColor` - background color of the inactive label
|
||||
- `onItemPress(route)` - function to be invoked when an item is pressed
|
||||
- `itemsContainerForceInset` - override default forceInset on the SafeAreaView that wraps the items container component
|
||||
- `itemsContainerStyle` - style object for the content section
|
||||
- `itemStyle` - style object for the single item, which can contain an Icon and/or a Label
|
||||
- `labelStyle` - style object to overwrite `Text` style inside content section, when your label is a string
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* @flow */
|
||||
|
||||
import React from 'react';
|
||||
import { Dimensions, Platform } from 'react-native';
|
||||
import { Dimensions, Platform, ScrollView } from 'react-native';
|
||||
|
||||
import createNavigator from './createNavigator';
|
||||
import createNavigationContainer from '../createNavigationContainer';
|
||||
@@ -9,6 +9,7 @@ import TabRouter from '../routers/TabRouter';
|
||||
import DrawerScreen from '../views/Drawer/DrawerScreen';
|
||||
import DrawerView from '../views/Drawer/DrawerView';
|
||||
import DrawerItems from '../views/Drawer/DrawerNavigatorItems';
|
||||
import SafeAreaView from '../views/SafeAreaView';
|
||||
|
||||
import NavigatorTypes from './NavigatorTypes';
|
||||
|
||||
@@ -25,13 +26,21 @@ export type DrawerNavigatorConfig = {
|
||||
|
||||
const { height, width } = Dimensions.get('window');
|
||||
|
||||
const defaultContentComponent = (props: *) => (
|
||||
<ScrollView alwaysBounceVertical={false}>
|
||||
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
|
||||
<DrawerItems {...props} />
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
const DefaultDrawerConfig = {
|
||||
/*
|
||||
* Default drawer width is screen width - header width
|
||||
* https://material.io/guidelines/patterns/navigation-drawer.html
|
||||
*/
|
||||
drawerWidth: Math.min(height, width) - (Platform.OS === 'android' ? 56 : 64),
|
||||
contentComponent: DrawerItems,
|
||||
contentComponent: defaultContentComponent,
|
||||
drawerPosition: 'left',
|
||||
drawerBackgroundColor: 'white',
|
||||
useNativeAnimations: true,
|
||||
|
||||
@@ -91,99 +91,146 @@ exports[`DrawerNavigator renders successfully 1`] = `
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
onLayout={[Function]}
|
||||
<RCTScrollView
|
||||
DEPRECATED_sendUpdatedChildFrames={false}
|
||||
alwaysBounceHorizontal={undefined}
|
||||
alwaysBounceVertical={false}
|
||||
onContentSizeChange={null}
|
||||
onMomentumScrollBegin={[Function]}
|
||||
onMomentumScrollEnd={[Function]}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderReject={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={undefined}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onScroll={[Function]}
|
||||
onScrollBeginDrag={[Function]}
|
||||
onScrollEndDrag={[Function]}
|
||||
onScrollShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onStartShouldSetResponderCapture={[Function]}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchMove={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
scrollEventThrottle={undefined}
|
||||
sendMomentumEvents={false}
|
||||
style={
|
||||
Object {
|
||||
"paddingBottom": 0,
|
||||
"paddingLeft": 0,
|
||||
"paddingRight": 0,
|
||||
"paddingTop": 20,
|
||||
}
|
||||
Array [
|
||||
Object {
|
||||
"flexDirection": "column",
|
||||
"flexGrow": 1,
|
||||
"flexShrink": 1,
|
||||
"overflow": "scroll",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
<RCTScrollContentView
|
||||
collapsable={false}
|
||||
removeClippedSubviews={undefined}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"paddingVertical": 4,
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
accessibilityComponentType={undefined}
|
||||
accessibilityLabel={undefined}
|
||||
accessibilityTraits={undefined}
|
||||
accessible={true}
|
||||
collapsable={undefined}
|
||||
hitSlop={undefined}
|
||||
isTVSelectable={true}
|
||||
nativeID={undefined}
|
||||
onLayout={undefined}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderMove={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={[Function]}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"opacity": 1,
|
||||
"paddingBottom": 0,
|
||||
"paddingLeft": 0,
|
||||
"paddingRight": 0,
|
||||
"paddingTop": 20,
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
tvParallaxProperties={undefined}
|
||||
>
|
||||
<View
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "rgba(0, 0, 0, .04)",
|
||||
"paddingBottom": 0,
|
||||
"paddingLeft": 0,
|
||||
"paddingRight": 0,
|
||||
"paddingTop": 20,
|
||||
}
|
||||
Array [
|
||||
Object {
|
||||
"paddingVertical": 4,
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
accessibilityComponentType={undefined}
|
||||
accessibilityLabel={undefined}
|
||||
accessibilityTraits={undefined}
|
||||
accessible={true}
|
||||
collapsable={undefined}
|
||||
hitSlop={undefined}
|
||||
isTVSelectable={true}
|
||||
nativeID={undefined}
|
||||
onLayout={undefined}
|
||||
onResponderGrant={[Function]}
|
||||
onResponderMove={[Function]}
|
||||
onResponderRelease={[Function]}
|
||||
onResponderTerminate={[Function]}
|
||||
onResponderTerminationRequest={[Function]}
|
||||
onStartShouldSetResponder={[Function]}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
Object {
|
||||
"opacity": 1,
|
||||
}
|
||||
}
|
||||
testID={undefined}
|
||||
tvParallaxProperties={undefined}
|
||||
>
|
||||
<Text
|
||||
accessible={true}
|
||||
allowFontScaling={true}
|
||||
disabled={false}
|
||||
ellipsizeMode="tail"
|
||||
<View
|
||||
onLayout={[Function]}
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"fontWeight": "bold",
|
||||
"margin": 16,
|
||||
},
|
||||
Object {
|
||||
"color": "#2196f3",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
Object {
|
||||
"backgroundColor": "rgba(0, 0, 0, .04)",
|
||||
"paddingBottom": 0,
|
||||
"paddingLeft": 0,
|
||||
"paddingRight": 0,
|
||||
"paddingTop": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
Welcome anonymous
|
||||
</Text>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"flexDirection": "row",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
<Text
|
||||
accessible={true}
|
||||
allowFontScaling={true}
|
||||
disabled={false}
|
||||
ellipsizeMode="tail"
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"fontWeight": "bold",
|
||||
"margin": 16,
|
||||
},
|
||||
Object {
|
||||
"color": "#2196f3",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
>
|
||||
Welcome anonymous
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</RCTScrollContentView>
|
||||
</RCTScrollView>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -31,6 +31,7 @@ type Props = {
|
||||
itemStyle?: ViewStyleProp,
|
||||
labelStyle?: TextStyleProp,
|
||||
iconContainerStyle?: ViewStyleProp,
|
||||
drawerPosition: 'left' | 'right',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -47,61 +48,63 @@ const DrawerNavigatorItems = ({
|
||||
getLabel,
|
||||
renderIcon,
|
||||
onItemPress,
|
||||
itemsContainerForceInset = { horizontal: 'never', top: 'always' },
|
||||
itemsContainerStyle,
|
||||
itemStyle,
|
||||
labelStyle,
|
||||
iconContainerStyle,
|
||||
drawerPosition,
|
||||
}: Props) => (
|
||||
<SafeAreaView forceInset={itemsContainerForceInset}>
|
||||
<View style={[styles.container, itemsContainerStyle]}>
|
||||
{items.map((route: NavigationRoute, index: number) => {
|
||||
const focused = activeItemKey === route.key;
|
||||
const color = focused ? activeTintColor : inactiveTintColor;
|
||||
const backgroundColor = focused
|
||||
? activeBackgroundColor
|
||||
: inactiveBackgroundColor;
|
||||
const scene = { route, index, focused, tintColor: color };
|
||||
const icon = renderIcon(scene);
|
||||
const label = getLabel(scene);
|
||||
return (
|
||||
<TouchableItem
|
||||
key={route.key}
|
||||
onPress={() => {
|
||||
onItemPress({ route, focused });
|
||||
<View style={[styles.container, itemsContainerStyle]}>
|
||||
{items.map((route: NavigationRoute, index: number) => {
|
||||
const focused = activeItemKey === route.key;
|
||||
const color = focused ? activeTintColor : inactiveTintColor;
|
||||
const backgroundColor = focused
|
||||
? activeBackgroundColor
|
||||
: inactiveBackgroundColor;
|
||||
const scene = { route, index, focused, tintColor: color };
|
||||
const icon = renderIcon(scene);
|
||||
const label = getLabel(scene);
|
||||
return (
|
||||
<TouchableItem
|
||||
key={route.key}
|
||||
onPress={() => {
|
||||
onItemPress({ route, focused });
|
||||
}}
|
||||
delayPressIn={0}
|
||||
>
|
||||
<SafeAreaView
|
||||
style={{ backgroundColor }}
|
||||
forceInset={{
|
||||
[drawerPosition]: 'always',
|
||||
[drawerPosition === 'left' ? 'right' : 'left']: 'never',
|
||||
vertical: 'never',
|
||||
}}
|
||||
delayPressIn={0}
|
||||
>
|
||||
<SafeAreaView
|
||||
style={{ backgroundColor }}
|
||||
forceInset={{ horizontal: 'always' }}
|
||||
>
|
||||
<View style={[styles.item, itemStyle]}>
|
||||
{icon ? (
|
||||
<View
|
||||
style={[
|
||||
styles.icon,
|
||||
focused ? null : styles.inactiveIcon,
|
||||
iconContainerStyle,
|
||||
]}
|
||||
>
|
||||
{icon}
|
||||
</View>
|
||||
) : null}
|
||||
{typeof label === 'string' ? (
|
||||
<Text style={[styles.label, { color }, labelStyle]}>
|
||||
{label}
|
||||
</Text>
|
||||
) : (
|
||||
label
|
||||
)}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</TouchableItem>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
<View style={[styles.item, itemStyle]}>
|
||||
{icon ? (
|
||||
<View
|
||||
style={[
|
||||
styles.icon,
|
||||
focused ? null : styles.inactiveIcon,
|
||||
iconContainerStyle,
|
||||
]}
|
||||
>
|
||||
{icon}
|
||||
</View>
|
||||
) : null}
|
||||
{typeof label === 'string' ? (
|
||||
<Text style={[styles.label, { color }, labelStyle]}>
|
||||
{label}
|
||||
</Text>
|
||||
) : (
|
||||
label
|
||||
)}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</TouchableItem>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
|
||||
/* Material design specs - https://material.io/guidelines/patterns/navigation-drawer.html#navigation-drawer-specs */
|
||||
|
||||
@@ -7,6 +7,8 @@ import withCachedChildNavigation from '../../withCachedChildNavigation';
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
import invariant from '../../utils/invariant';
|
||||
|
||||
import SafeAreaView from '../SafeAreaView';
|
||||
|
||||
import type {
|
||||
NavigationScreenProp,
|
||||
NavigationRoute,
|
||||
@@ -34,6 +36,7 @@ type Props = {
|
||||
contentOptions?: {},
|
||||
screenProps?: {},
|
||||
style?: ViewStyleProp,
|
||||
drawerPosition?: 'left' | 'right',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -123,6 +126,7 @@ class DrawerSidebar extends React.PureComponent<Props> {
|
||||
renderIcon={this._renderIcon}
|
||||
onItemPress={this._onItemPress}
|
||||
router={this.props.router}
|
||||
drawerPosition={this.props.drawerPosition}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -134,6 +134,7 @@ export default class DrawerView<T: NavigationRoute> extends React.PureComponent<
|
||||
router={this.props.router}
|
||||
contentComponent={this.props.contentComponent}
|
||||
contentOptions={this.props.contentOptions}
|
||||
drawerPosition={this.props.drawerPosition}
|
||||
style={this.props.style}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user