mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-12 22:51:18 +08:00
refactor: use react-native-safe-area-context
This commit is contained in:
committed by
Satyajit Sahoo
parent
8318c49331
commit
832ed882bc
@@ -41,9 +41,8 @@
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"react": "16.8.3",
|
||||
"react-native": "0.59.10",
|
||||
"react-native-safe-area-view": "0.14.7"
|
||||
"react": "16.10.1",
|
||||
"react-native": "0.59.10"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
||||
@@ -10,6 +10,30 @@ Open a Terminal in your project's folder and run,
|
||||
yarn add @react-navigation/core @react-navigation/bottom-tabs
|
||||
```
|
||||
|
||||
Now we need to install [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context).
|
||||
|
||||
If you are using Expo, to ensure that you get the compatible versions of the libraries, run:
|
||||
|
||||
```sh
|
||||
expo install react-native-safe-area-context
|
||||
```
|
||||
|
||||
If you are not using Expo, run the following:
|
||||
|
||||
```sh
|
||||
yarn add react-native-safe-area-context
|
||||
```
|
||||
|
||||
If you are using Expo, you are done. Otherwise, continue to the next steps.
|
||||
|
||||
To complete the linking on iOS, make sure you have [Cocoapods](https://cocoapods.org/) installed. Then run:
|
||||
|
||||
```sh
|
||||
cd ios
|
||||
pod install
|
||||
cd ..
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
|
||||
@@ -33,22 +33,23 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.9",
|
||||
"react-native-safe-area-view": "^0.14.7"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
"@types/react": "^16.9.4",
|
||||
"@types/react-native": "^0.60.17",
|
||||
"del-cli": "^3.0.0",
|
||||
"react": "16.8.3",
|
||||
"react": "16.10.1",
|
||||
"react-native": "0.59.10",
|
||||
"react-native-safe-area-context": "^0.3.6",
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/core": "^5.0.0-alpha.0",
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": "^0.3.6"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
"source": "src",
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
TextStyle,
|
||||
ViewStyle,
|
||||
} from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import {
|
||||
NavigationHelpers,
|
||||
NavigationProp,
|
||||
@@ -234,5 +233,4 @@ export type BottomTabBarProps = BottomTabBarOptions & {
|
||||
}) => React.ReactNode;
|
||||
activeTintColor: string;
|
||||
inactiveTintColor: string;
|
||||
safeAreaInset?: React.ComponentProps<typeof SafeAreaView>['forceInset'];
|
||||
};
|
||||
|
||||
@@ -8,8 +8,8 @@ import {
|
||||
ScaledSize,
|
||||
Dimensions,
|
||||
} from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { Route, NavigationContext } from '@react-navigation/core';
|
||||
import { SafeAreaConsumer } from 'react-native-safe-area-context';
|
||||
|
||||
import TabBarIcon from './TabBarIcon';
|
||||
import TouchableWithoutFeedbackWrapper from './TouchableWithoutFeedbackWrapper';
|
||||
@@ -22,9 +22,7 @@ type State = {
|
||||
visible: Animated.Value;
|
||||
};
|
||||
|
||||
type Props = BottomTabBarProps & {
|
||||
safeAreaInset: React.ComponentProps<typeof SafeAreaView>['forceInset'];
|
||||
};
|
||||
type Props = BottomTabBarProps;
|
||||
|
||||
const majorVersion = parseInt(Platform.Version as string, 10);
|
||||
const isIos = Platform.OS === 'ios';
|
||||
@@ -43,9 +41,6 @@ export default class TabBarBottom extends React.Component<Props, State> {
|
||||
showIcon: true,
|
||||
allowFontScaling: true,
|
||||
adaptive: isIOS11,
|
||||
safeAreaInset: { bottom: 'always', top: 'never' } as React.ComponentProps<
|
||||
typeof SafeAreaView
|
||||
>['forceInset'],
|
||||
};
|
||||
|
||||
state = {
|
||||
@@ -270,99 +265,101 @@ export default class TabBarBottom extends React.Component<Props, State> {
|
||||
getAccessibilityStates,
|
||||
getButtonComponent,
|
||||
getTestID,
|
||||
safeAreaInset,
|
||||
style,
|
||||
tabStyle,
|
||||
} = this.props;
|
||||
const { routes } = state;
|
||||
|
||||
const tabBarStyle = [
|
||||
styles.tabBar,
|
||||
// @ts-ignore
|
||||
this.shouldUseHorizontalLabels() && !Platform.isPad
|
||||
? styles.tabBarCompact
|
||||
: styles.tabBarRegular,
|
||||
style,
|
||||
];
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.container,
|
||||
keyboardHidesTabBar
|
||||
? {
|
||||
// When the keyboard is shown, slide down the tab bar
|
||||
transform: [
|
||||
{
|
||||
translateY: this.state.visible.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [this.state.layout.height, 0],
|
||||
}),
|
||||
},
|
||||
],
|
||||
// Absolutely position the tab bar so that the content is below it
|
||||
// This is needed to avoid gap at bottom when the tab bar is hidden
|
||||
position: this.state.keyboard ? 'absolute' : null,
|
||||
}
|
||||
: null,
|
||||
]}
|
||||
pointerEvents={
|
||||
keyboardHidesTabBar && this.state.keyboard ? 'none' : 'auto'
|
||||
}
|
||||
onLayout={this.handleLayout}
|
||||
>
|
||||
<SafeAreaView style={tabBarStyle} forceInset={safeAreaInset}>
|
||||
{routes.map((route, index) => {
|
||||
const focused = index === state.index;
|
||||
const scene = { route, focused };
|
||||
const accessibilityLabel = getAccessibilityLabel({
|
||||
route,
|
||||
});
|
||||
<SafeAreaConsumer>
|
||||
{insets => (
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.tabBar,
|
||||
keyboardHidesTabBar
|
||||
? {
|
||||
// When the keyboard is shown, slide down the tab bar
|
||||
transform: [
|
||||
{
|
||||
translateY: this.state.visible.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [this.state.layout.height, 0],
|
||||
}),
|
||||
},
|
||||
],
|
||||
// Absolutely position the tab bar so that the content is below it
|
||||
// This is needed to avoid gap at bottom when the tab bar is hidden
|
||||
position: this.state.keyboard ? 'absolute' : null,
|
||||
}
|
||||
: null,
|
||||
{
|
||||
height:
|
||||
// @ts-ignore
|
||||
(this.shouldUseHorizontalLabels() && !Platform.isPad
|
||||
? COMPACT_HEIGHT
|
||||
: DEFAULT_HEIGHT) + (insets ? insets.bottom : 0),
|
||||
paddingBottom: insets ? insets.bottom : 0,
|
||||
},
|
||||
style,
|
||||
]}
|
||||
pointerEvents={
|
||||
keyboardHidesTabBar && this.state.keyboard ? 'none' : 'auto'
|
||||
}
|
||||
onLayout={this.handleLayout}
|
||||
>
|
||||
{routes.map((route, index) => {
|
||||
const focused = index === state.index;
|
||||
const scene = { route, focused };
|
||||
const accessibilityLabel = getAccessibilityLabel({
|
||||
route,
|
||||
});
|
||||
|
||||
const accessibilityRole = getAccessibilityRole({
|
||||
route,
|
||||
});
|
||||
const accessibilityRole = getAccessibilityRole({
|
||||
route,
|
||||
});
|
||||
|
||||
const accessibilityStates = getAccessibilityStates(scene);
|
||||
const accessibilityStates = getAccessibilityStates(scene);
|
||||
|
||||
const testID = getTestID({ route });
|
||||
const testID = getTestID({ route });
|
||||
|
||||
const backgroundColor = focused
|
||||
? activeBackgroundColor
|
||||
: inactiveBackgroundColor;
|
||||
const backgroundColor = focused
|
||||
? activeBackgroundColor
|
||||
: inactiveBackgroundColor;
|
||||
|
||||
const ButtonComponent =
|
||||
getButtonComponent({ route }) || TouchableWithoutFeedbackWrapper;
|
||||
const ButtonComponent =
|
||||
getButtonComponent({ route }) ||
|
||||
TouchableWithoutFeedbackWrapper;
|
||||
|
||||
return (
|
||||
<NavigationContext.Provider
|
||||
key={route.key}
|
||||
value={descriptors[route.key].navigation}
|
||||
>
|
||||
<ButtonComponent
|
||||
onPress={() => onTabPress({ route })}
|
||||
onLongPress={() => onTabLongPress({ route })}
|
||||
testID={testID}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
accessibilityRole={accessibilityRole}
|
||||
accessibilityStates={accessibilityStates}
|
||||
style={[
|
||||
styles.tab,
|
||||
{ backgroundColor },
|
||||
this.shouldUseHorizontalLabels()
|
||||
? styles.tabLandscape
|
||||
: styles.tabPortrait,
|
||||
tabStyle,
|
||||
]}
|
||||
return (
|
||||
<NavigationContext.Provider
|
||||
key={route.key}
|
||||
value={descriptors[route.key].navigation}
|
||||
>
|
||||
{this.renderIcon(scene)}
|
||||
{this.renderLabel(scene)}
|
||||
</ButtonComponent>
|
||||
</NavigationContext.Provider>
|
||||
);
|
||||
})}
|
||||
</SafeAreaView>
|
||||
</Animated.View>
|
||||
<ButtonComponent
|
||||
onPress={() => onTabPress({ route })}
|
||||
onLongPress={() => onTabLongPress({ route })}
|
||||
testID={testID}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
accessibilityRole={accessibilityRole}
|
||||
accessibilityStates={accessibilityStates}
|
||||
style={[
|
||||
styles.tab,
|
||||
{ backgroundColor },
|
||||
this.shouldUseHorizontalLabels()
|
||||
? styles.tabLandscape
|
||||
: styles.tabPortrait,
|
||||
tabStyle,
|
||||
]}
|
||||
>
|
||||
{this.renderIcon(scene)}
|
||||
{this.renderLabel(scene)}
|
||||
</ButtonComponent>
|
||||
</NavigationContext.Provider>
|
||||
);
|
||||
})}
|
||||
</Animated.View>
|
||||
)}
|
||||
</SafeAreaConsumer>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -372,23 +369,15 @@ const COMPACT_HEIGHT = 29;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tabBar: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: '#fff',
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: 'rgba(0, 0, 0, .3)',
|
||||
flexDirection: 'row',
|
||||
},
|
||||
container: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
elevation: 8,
|
||||
},
|
||||
tabBarCompact: {
|
||||
height: COMPACT_HEIGHT,
|
||||
},
|
||||
tabBarRegular: {
|
||||
height: DEFAULT_HEIGHT,
|
||||
},
|
||||
tab: {
|
||||
flex: 1,
|
||||
alignItems: isIos ? 'center' : 'stretch',
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Route, CommonActions } from '@react-navigation/core';
|
||||
import { TabNavigationState } from '@react-navigation/routers';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { ScreenContainer } from 'react-native-screens';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
|
||||
import BottomTabBar from './BottomTabBar';
|
||||
import {
|
||||
@@ -198,29 +199,31 @@ export default class BottomTabView extends React.Component<Props, State> {
|
||||
const { loaded } = this.state;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ScreenContainer style={styles.pages}>
|
||||
{routes.map((route, index) => {
|
||||
if (lazy && !loaded.includes(index)) {
|
||||
// Don't render a screen if we've never navigated to it
|
||||
return null;
|
||||
}
|
||||
<SafeAreaProvider>
|
||||
<View style={styles.container}>
|
||||
<ScreenContainer style={styles.pages}>
|
||||
{routes.map((route, index) => {
|
||||
if (lazy && !loaded.includes(index)) {
|
||||
// Don't render a screen if we've never navigated to it
|
||||
return null;
|
||||
}
|
||||
|
||||
const isFocused = state.index === index;
|
||||
const isFocused = state.index === index;
|
||||
|
||||
return (
|
||||
<ResourceSavingScene
|
||||
key={route.key}
|
||||
style={StyleSheet.absoluteFill}
|
||||
isVisible={isFocused}
|
||||
>
|
||||
{descriptors[route.key].render()}
|
||||
</ResourceSavingScene>
|
||||
);
|
||||
})}
|
||||
</ScreenContainer>
|
||||
{this.renderTabBar()}
|
||||
</View>
|
||||
return (
|
||||
<ResourceSavingScene
|
||||
key={route.key}
|
||||
style={StyleSheet.absoluteFill}
|
||||
isVisible={isFocused}
|
||||
>
|
||||
{descriptors[route.key].render()}
|
||||
</ResourceSavingScene>
|
||||
);
|
||||
})}
|
||||
</ScreenContainer>
|
||||
{this.renderTabBar()}
|
||||
</View>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^16.9.4",
|
||||
"react": "^16.8.3",
|
||||
"react": "^16.10.1",
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/core": "^5.0.0-alpha.0",
|
||||
"react": "^16.8.3"
|
||||
"react": "^16.10.1"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
"source": "src",
|
||||
|
||||
@@ -40,13 +40,13 @@
|
||||
"@types/react": "^16.9.4",
|
||||
"@types/shortid": "^0.0.29",
|
||||
"del-cli": "^3.0.0",
|
||||
"react": "^16.8.3",
|
||||
"react": "^16.10.1",
|
||||
"react-native-testing-library": "^1.9.1",
|
||||
"react-test-renderer": "16.8.3",
|
||||
"react-test-renderer": "16.10.1",
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.3"
|
||||
"react": "^16.10.1"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
"source": "src",
|
||||
|
||||
@@ -273,7 +273,11 @@ it('fires blur event when a route is removed with a delay', async () => {
|
||||
|
||||
const [previous, dispatch] = React.useReducer(
|
||||
(state, action) => {
|
||||
return { ...state, ...action };
|
||||
if (state.routes !== action.routes) {
|
||||
return { ...state, ...action };
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
{ routes: state.routes, descriptors }
|
||||
);
|
||||
|
||||
@@ -10,44 +10,29 @@ Open a Terminal in your project's folder and run,
|
||||
yarn add @react-navigation/core @react-navigation/drawer
|
||||
```
|
||||
|
||||
Now we need to install [`react-native-gesture-handler`](https://github.com/kmagiera/react-native-gesture-handler) and [`react-native-reanimated`](https://github.com/kmagiera/react-native-reanimated).
|
||||
Now we need to install [`react-native-gesture-handler`](https://github.com/kmagiera/react-native-gesture-handler), [`react-native-reanimated`](https://github.com/kmagiera/react-native-reanimated) and [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context).
|
||||
|
||||
If you are using Expo, to ensure that you get the compatible versions of the libraries, run:
|
||||
|
||||
```sh
|
||||
expo install react-native-gesture-handler react-native-reanimated
|
||||
expo install react-native-gesture-handler react-native-reanimated react-native-safe-area-context
|
||||
```
|
||||
|
||||
If you are not using Expo, run the following:
|
||||
|
||||
```sh
|
||||
yarn add react-native-reanimated react-native-gesture-handler
|
||||
yarn add react-native-reanimated react-native-gesture-handler react-native-safe-area-context
|
||||
```
|
||||
|
||||
If you are using Expo, you are done. Otherwise, continue to the next steps.
|
||||
|
||||
Next, we need to link these libraries. The steps depends on your React Native version:
|
||||
To complete the linking on iOS, make sure you have [Cocoapods](https://cocoapods.org/) installed. Then run:
|
||||
|
||||
- **React Native 0.60 and higher**
|
||||
|
||||
On newer versions of React Native, [linking is automatic](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md).
|
||||
|
||||
To complete the linking on iOS, make sure you have [Cocoapods](https://cocoapods.org/) installed. Then run:
|
||||
|
||||
```sh
|
||||
cd ios
|
||||
pod install
|
||||
cd ..
|
||||
```
|
||||
|
||||
- **React Native 0.59**
|
||||
|
||||
If you're on an older React Native version, you need to manually link the dependencies. To do that, run:
|
||||
|
||||
```sh
|
||||
react-native link react-native-reanimated
|
||||
react-native link react-native-gesture-handler
|
||||
```
|
||||
```sh
|
||||
cd ios
|
||||
pod install
|
||||
cd ..
|
||||
```
|
||||
|
||||
**IMPORTANT:** There are additional steps required for `react-native-gesture-handler` on Android after linking (for all React Native versions). Check the [this guide](https://kmagiera.github.io/react-native-gesture-handler/docs/getting-started.html) to complete the installation.
|
||||
|
||||
|
||||
@@ -34,18 +34,18 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.9",
|
||||
"react-native-safe-area-view": "^0.14.7"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
"@types/react": "^16.9.4",
|
||||
"@types/react-native": "^0.60.17",
|
||||
"del-cli": "^3.0.0",
|
||||
"react": "16.8.3",
|
||||
"react": "16.10.1",
|
||||
"react-native": "0.59.10",
|
||||
"react-native-gesture-handler": "^1.3.0",
|
||||
"react-native-reanimated": "^1.3.0",
|
||||
"react-native-safe-area-context": "^0.3.6",
|
||||
"react-native-screens": "^1.0.0-alpha.22",
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
@@ -55,6 +55,7 @@
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": "^1.0.0",
|
||||
"react-native-reanimated": "^1.0.0",
|
||||
"react-native-safe-area-context": "^0.3.6",
|
||||
"react-native-screens": "^1.0.0-alpha.0"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { View, Text, StyleSheet } from 'react-native';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { useSafeArea } from 'react-native-safe-area-context';
|
||||
|
||||
import TouchableItem from './TouchableItem';
|
||||
import { DrawerNavigationItemsProps } from '../types';
|
||||
@@ -25,63 +25,72 @@ const DrawerNavigatorItems = ({
|
||||
inactiveLabelStyle,
|
||||
iconContainerStyle,
|
||||
drawerPosition,
|
||||
}: DrawerNavigationItemsProps) => (
|
||||
<View style={[styles.container, itemsContainerStyle]}>
|
||||
{items.map((route, 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);
|
||||
const accessibilityLabel = typeof label === 'string' ? label : undefined;
|
||||
const extraLabelStyle = focused ? activeLabelStyle : inactiveLabelStyle;
|
||||
return (
|
||||
<TouchableItem
|
||||
key={route.key}
|
||||
accessible
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onPress={() => {
|
||||
onItemPress({ route, focused });
|
||||
}}
|
||||
delayPressIn={0}
|
||||
>
|
||||
<SafeAreaView
|
||||
style={[{ backgroundColor }, styles.item, itemStyle]}
|
||||
forceInset={{
|
||||
[drawerPosition]: 'always',
|
||||
[drawerPosition === 'left' ? 'right' : 'left']: 'never',
|
||||
vertical: 'never',
|
||||
}: DrawerNavigationItemsProps) => {
|
||||
const insets = useSafeArea();
|
||||
|
||||
return (
|
||||
<View style={[styles.container, itemsContainerStyle]}>
|
||||
{items.map((route, 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);
|
||||
const accessibilityLabel =
|
||||
typeof label === 'string' ? label : undefined;
|
||||
const extraLabelStyle = focused ? activeLabelStyle : inactiveLabelStyle;
|
||||
|
||||
return (
|
||||
<TouchableItem
|
||||
key={route.key}
|
||||
accessible
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
onPress={() => {
|
||||
onItemPress({ route, focused });
|
||||
}}
|
||||
delayPressIn={0}
|
||||
>
|
||||
{icon ? (
|
||||
<View
|
||||
style={[
|
||||
styles.icon,
|
||||
focused ? null : styles.inactiveIcon,
|
||||
iconContainerStyle,
|
||||
]}
|
||||
>
|
||||
{icon}
|
||||
</View>
|
||||
) : null}
|
||||
{typeof label === 'string' ? (
|
||||
<Text
|
||||
style={[styles.label, { color }, labelStyle, extraLabelStyle]}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
) : (
|
||||
label
|
||||
)}
|
||||
</SafeAreaView>
|
||||
</TouchableItem>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
backgroundColor,
|
||||
marginLeft: drawerPosition === 'left' ? insets.left : 0,
|
||||
marginRight: drawerPosition === 'right' ? insets.right : 0,
|
||||
},
|
||||
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, extraLabelStyle]}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
) : (
|
||||
label
|
||||
)}
|
||||
</View>
|
||||
</TouchableItem>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
/* Material design specs - https://material.io/guidelines/patterns/navigation-drawer.html#navigation-drawer-specs */
|
||||
DrawerNavigatorItems.defaultProps = {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import { Dimensions, StyleSheet, I18nManager, Platform } from 'react-native';
|
||||
import { SafeAreaProvider, useSafeArea } from 'react-native-safe-area-context';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { ScreenContainer } from 'react-native-screens';
|
||||
import SafeAreaView from 'react-native-safe-area-view';
|
||||
import { PanGestureHandler, ScrollView } from 'react-native-gesture-handler';
|
||||
import {
|
||||
DrawerNavigationState,
|
||||
@@ -32,13 +32,18 @@ type State = {
|
||||
drawerWidth: number;
|
||||
};
|
||||
|
||||
const DefaultContentComponent = (props: ContentComponentProps) => (
|
||||
<ScrollView alwaysBounceVertical={false}>
|
||||
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
|
||||
const DefaultContentComponent = (props: ContentComponentProps) => {
|
||||
const insets = useSafeArea();
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
alwaysBounceVertical={false}
|
||||
contentContainerStyle={{ marginTop: insets.top }}
|
||||
>
|
||||
<DrawerNavigatorItems {...props} />
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
);
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Component that renders the drawer.
|
||||
@@ -208,35 +213,37 @@ export default class DrawerView extends React.PureComponent<Props, State> {
|
||||
: state.isDrawerOpen;
|
||||
|
||||
return (
|
||||
<DrawerGestureContext.Provider value={this.drawerGestureRef}>
|
||||
<Drawer
|
||||
open={isOpen}
|
||||
locked={
|
||||
drawerLockMode === 'locked-open' ||
|
||||
drawerLockMode === 'locked-closed'
|
||||
}
|
||||
onOpen={this.handleDrawerOpen}
|
||||
onClose={this.handleDrawerClose}
|
||||
onGestureRef={this.setDrawerGestureRef}
|
||||
gestureHandlerProps={gestureHandlerProps}
|
||||
drawerType={drawerType}
|
||||
drawerPosition={drawerPosition}
|
||||
sceneContainerStyle={sceneContainerStyle}
|
||||
drawerStyle={{
|
||||
backgroundColor: drawerBackgroundColor || 'white',
|
||||
width: this.state.drawerWidth,
|
||||
}}
|
||||
overlayStyle={{
|
||||
backgroundColor: overlayColor || 'rgba(0, 0, 0, 0.5)',
|
||||
}}
|
||||
swipeEdgeWidth={edgeWidth}
|
||||
swipeDistanceThreshold={minSwipeDistance}
|
||||
hideStatusBar={hideStatusBar}
|
||||
statusBarAnimation={statusBarAnimation}
|
||||
renderDrawerContent={this.renderNavigationView}
|
||||
renderSceneContent={this.renderContent}
|
||||
/>
|
||||
</DrawerGestureContext.Provider>
|
||||
<SafeAreaProvider>
|
||||
<DrawerGestureContext.Provider value={this.drawerGestureRef}>
|
||||
<Drawer
|
||||
open={isOpen}
|
||||
locked={
|
||||
drawerLockMode === 'locked-open' ||
|
||||
drawerLockMode === 'locked-closed'
|
||||
}
|
||||
onOpen={this.handleDrawerOpen}
|
||||
onClose={this.handleDrawerClose}
|
||||
onGestureRef={this.setDrawerGestureRef}
|
||||
gestureHandlerProps={gestureHandlerProps}
|
||||
drawerType={drawerType}
|
||||
drawerPosition={drawerPosition}
|
||||
sceneContainerStyle={sceneContainerStyle}
|
||||
drawerStyle={{
|
||||
backgroundColor: drawerBackgroundColor || 'white',
|
||||
width: this.state.drawerWidth,
|
||||
}}
|
||||
overlayStyle={{
|
||||
backgroundColor: overlayColor || 'rgba(0, 0, 0, 0.5)',
|
||||
}}
|
||||
swipeEdgeWidth={edgeWidth}
|
||||
swipeDistanceThreshold={minSwipeDistance}
|
||||
hideStatusBar={hideStatusBar}
|
||||
statusBarAnimation={statusBarAnimation}
|
||||
renderDrawerContent={this.renderNavigationView}
|
||||
renderSceneContent={this.renderContent}
|
||||
/>
|
||||
</DrawerGestureContext.Provider>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
"name": "@react-navigation/example",
|
||||
"slug": "react-navigation-example",
|
||||
"privacy": "public",
|
||||
"sdkVersion": "34.0.0",
|
||||
"sdkVersion": "35.0.0",
|
||||
"platforms": [
|
||||
"ios",
|
||||
"android",
|
||||
"web"
|
||||
],
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"splash": {
|
||||
"image": "./assets/splash.png",
|
||||
@@ -30,4 +29,4 @@
|
||||
},
|
||||
"displayName": "React Navigation Example",
|
||||
"name": "ReactNavigationExample"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ module.exports = {
|
||||
'react-native',
|
||||
'react-native-gesture-handler',
|
||||
'react-native-reanimated',
|
||||
'react-native-safe-area-view',
|
||||
'react-native-safe-area-context',
|
||||
'react-native-screens',
|
||||
'react-native-paper',
|
||||
'react-native-tab-view',
|
||||
|
||||
@@ -22,11 +22,12 @@
|
||||
"expo-asset": "~7.0.0",
|
||||
"query-string": "^6.8.3",
|
||||
"react": "^16.10.1",
|
||||
"react-dom": "^16.8.3",
|
||||
"react-dom": "^16.10.1",
|
||||
"react-native": "^0.61.2",
|
||||
"react-native-gesture-handler": "~1.3.0",
|
||||
"react-native-paper": "^3.0.0-alpha.3",
|
||||
"react-native-reanimated": "~1.2.0",
|
||||
"react-native-safe-area-context": "~0.3.6",
|
||||
"react-native-screens": "~1.0.0-alpha.23",
|
||||
"react-native-tab-view": "2.10.0",
|
||||
"react-native-unimodules": "^0.7.0-rc.1",
|
||||
@@ -41,8 +42,5 @@
|
||||
"babel-preset-expo": "^7.0.0",
|
||||
"expo-cli": "^3.1.2",
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"react-native-safe-area-view": "0.14.7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"@types/react-native": "^0.60.17",
|
||||
"@types/react-native-vector-icons": "^6.4.4",
|
||||
"del-cli": "^3.0.0",
|
||||
"react": "16.8.3",
|
||||
"react": "16.10.1",
|
||||
"react-native": "0.59.10",
|
||||
"react-native-paper": "^3.0.0-alpha.3",
|
||||
"react-native-vector-icons": "^6.6.0",
|
||||
|
||||
@@ -10,7 +10,7 @@ Open a Terminal in your project's folder and run,
|
||||
yarn add @react-navigation/core @react-navigation/material-top-tabs react-native-tab-view
|
||||
```
|
||||
|
||||
Now we need to install [`react-native-gesture-handler`](https://github.com/kmagiera/react-native-gesture-handler) and [`react-native-reanimated`](https://github.com/kmagiera/react-native-reanimated).
|
||||
Now we need to install [`react-native-gesture-handler`](https://github.com/kmagiera/react-native-gesture-handler) and [`react-native-reanimated`](https://github.com/kmagiera/react-native-reanimated)..
|
||||
|
||||
If you are using Expo, to ensure that you get the compatible versions of the libraries, run:
|
||||
|
||||
@@ -26,28 +26,13 @@ yarn add react-native-reanimated react-native-gesture-handler
|
||||
|
||||
If you are using Expo, you are done. Otherwise, continue to the next steps.
|
||||
|
||||
Next, we need to link these libraries. The steps depends on your React Native version:
|
||||
To complete the linking on iOS, make sure you have [Cocoapods](https://cocoapods.org/) installed. Then run:
|
||||
|
||||
- **React Native 0.60 and higher**
|
||||
|
||||
On newer versions of React Native, [linking is automatic](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md).
|
||||
|
||||
To complete the linking on iOS, make sure you have [Cocoapods](https://cocoapods.org/) installed. Then run:
|
||||
|
||||
```sh
|
||||
cd ios
|
||||
pod install
|
||||
cd ..
|
||||
```
|
||||
|
||||
- **React Native 0.59**
|
||||
|
||||
If you're on an older React Native version, you need to manually link the dependencies. To do that, run:
|
||||
|
||||
```sh
|
||||
react-native link react-native-reanimated
|
||||
react-native link react-native-gesture-handler
|
||||
```
|
||||
```sh
|
||||
cd ios
|
||||
pod install
|
||||
cd ..
|
||||
```
|
||||
|
||||
**IMPORTANT:** There are additional steps required for `react-native-gesture-handler` on Android after linking (for all React Native versions). Check the [this guide](https://kmagiera.github.io/react-native-gesture-handler/docs/getting-started.html) to complete the installation.
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"@types/react": "^16.9.4",
|
||||
"@types/react-native": "^0.60.17",
|
||||
"del-cli": "^3.0.0",
|
||||
"react": "16.8.3",
|
||||
"react": "16.10.1",
|
||||
"react-native": "^0.59.8",
|
||||
"react-native-gesture-handler": "^1.3.0",
|
||||
"react-native-reanimated": "^1.3.0",
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"@types/react": "^16.9.4",
|
||||
"@types/react-native": "^0.60.17",
|
||||
"del-cli": "^3.0.0",
|
||||
"react": "16.8.3",
|
||||
"react": "16.10.1",
|
||||
"react-native": "0.59.10",
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
|
||||
@@ -10,44 +10,36 @@ Open a Terminal in your project's folder and run,
|
||||
yarn add @react-navigation/core @react-navigation/stack @react-native-community/masked-view
|
||||
```
|
||||
|
||||
Now we need to install [`react-native-gesture-handler`](https://github.com/kmagiera/react-native-gesture-handler) and [`react-native-reanimated`](https://github.com/kmagiera/react-native-reanimated).
|
||||
Now we need to install [`react-native-gesture-handler`](https://github.com/kmagiera/react-native-gesture-handler), [`react-native-reanimated`](https://github.com/kmagiera/react-native-reanimated), [`react-native-screens`](https://github.com/kmagiera/react-native-screens) and [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context).
|
||||
|
||||
If you are using Expo, to ensure that you get the compatible versions of the libraries, run:
|
||||
|
||||
```sh
|
||||
expo install react-native-gesture-handler react-native-reanimated
|
||||
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context
|
||||
```
|
||||
|
||||
If you are not using Expo, run the following:
|
||||
|
||||
```sh
|
||||
yarn add react-native-reanimated react-native-gesture-handler
|
||||
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context
|
||||
```
|
||||
|
||||
If you are using Expo, you are done. Otherwise, continue to the next steps.
|
||||
|
||||
Next, we need to link these libraries. The steps depends on your React Native version:
|
||||
To complete the linking on iOS, make sure you have [Cocoapods](https://cocoapods.org/) installed. Then run:
|
||||
|
||||
- **React Native 0.60 and higher**
|
||||
```sh
|
||||
cd ios
|
||||
pod install
|
||||
cd ..
|
||||
```
|
||||
|
||||
On newer versions of React Native, [linking is automatic](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md).
|
||||
To finalize installation of `react-native-screens` for Android, add the following two lines to dependencies section in `android/app/build.gradle`:
|
||||
|
||||
To complete the linking on iOS, make sure you have [Cocoapods](https://cocoapods.org/) installed. Then run:
|
||||
|
||||
```sh
|
||||
cd ios
|
||||
pod install
|
||||
cd ..
|
||||
```
|
||||
|
||||
- **React Native 0.59**
|
||||
|
||||
If you're on an older React Native version, you need to manually link the dependencies. To do that, run:
|
||||
|
||||
```sh
|
||||
react-native link react-native-reanimated
|
||||
react-native link react-native-gesture-handler
|
||||
```
|
||||
```gradle
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'
|
||||
```
|
||||
|
||||
**IMPORTANT:** There are additional steps required for `react-native-gesture-handler` on Android after linking (for all React Native versions). Check the [this guide](https://kmagiera.github.io/react-native-gesture-handler/docs/getting-started.html) to complete the installation.
|
||||
|
||||
|
||||
@@ -33,8 +33,7 @@
|
||||
"clean": "del lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^5.0.0-alpha.9",
|
||||
"react-native-safe-area-view": "^0.14.7"
|
||||
"@react-navigation/routers": "^5.0.0-alpha.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-native-community/bob": "^0.7.0",
|
||||
@@ -42,10 +41,11 @@
|
||||
"@types/react": "^16.9.4",
|
||||
"@types/react-native": "^0.60.17",
|
||||
"del-cli": "^3.0.0",
|
||||
"react": "16.8.3",
|
||||
"react": "16.10.1",
|
||||
"react-native": "0.59.10",
|
||||
"react-native-gesture-handler": "^1.3.0",
|
||||
"react-native-reanimated": "^1.3.0",
|
||||
"react-native-safe-area-context": "^0.3.6",
|
||||
"react-native-screens": "^1.0.0-alpha.22",
|
||||
"typescript": "^3.6.3"
|
||||
},
|
||||
@@ -56,6 +56,7 @@
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": "^1.0.0",
|
||||
"react-native-reanimated": "^1.0.0",
|
||||
"react-native-safe-area-context": "^0.3.6",
|
||||
"react-native-screens": "^1.0.0-alpha.0"
|
||||
},
|
||||
"@react-native-community/bob": {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { I18nManager } from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import getStatusBarHeight from '../utils/getStatusBarHeight';
|
||||
import {
|
||||
StackCardInterpolationProps,
|
||||
StackCardInterpolatedStyle,
|
||||
@@ -84,9 +83,10 @@ export function forModalPresentationIOS({
|
||||
current,
|
||||
next,
|
||||
layouts: { screen },
|
||||
insets,
|
||||
}: StackCardInterpolationProps): StackCardInterpolatedStyle {
|
||||
const topOffset = 10;
|
||||
const statusBarHeight = getStatusBarHeight(screen.width > screen.height);
|
||||
const statusBarHeight = insets.top;
|
||||
const aspectRatio = screen.height / screen.width;
|
||||
|
||||
const progress = add(current.progress, next ? next.progress : 0);
|
||||
|
||||
@@ -184,10 +184,6 @@ export type StackHeaderOptions = {
|
||||
* Style object for the header. You can specify a custom background color here, for example.
|
||||
*/
|
||||
headerStyle?: StyleProp<ViewStyle>;
|
||||
/**
|
||||
* Custom status bar height to set as the top padding in the header.
|
||||
*/
|
||||
headerStatusBarHeight?: number;
|
||||
/**
|
||||
* Defaults to `false`. If `true`, the header will not have a background unless you explicitly provide it with `headerBackground`.
|
||||
* The header will also float over the screen so that it overlaps the content underneath.
|
||||
@@ -445,6 +441,15 @@ export type StackCardInterpolationProps = {
|
||||
*/
|
||||
screen: Layout;
|
||||
};
|
||||
/**
|
||||
* Safe area insets
|
||||
*/
|
||||
insets: {
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type StackCardInterpolatedStyle = {
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Platform } from 'react-native';
|
||||
import { getStatusBarHeight as getStatusBarHeightNative } from 'react-native-safe-area-view';
|
||||
|
||||
const getStatusBarHeight = Platform.select({
|
||||
default: getStatusBarHeightNative,
|
||||
web: () => 0,
|
||||
});
|
||||
|
||||
export default getStatusBarHeight;
|
||||
@@ -1,10 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import { StackActions } from '@react-navigation/routers';
|
||||
import { useSafeArea } from 'react-native-safe-area-context';
|
||||
|
||||
import HeaderSegment from './HeaderSegment';
|
||||
import { StackHeaderProps, StackHeaderTitleProps } from '../../types';
|
||||
import HeaderTitle from './HeaderTitle';
|
||||
|
||||
export default React.memo(function Header(props: StackHeaderProps) {
|
||||
const insets = useSafeArea();
|
||||
|
||||
const { scene, previous, layout, navigation, styleInterpolator } = props;
|
||||
const { options } = scene.descriptor;
|
||||
const title =
|
||||
@@ -35,6 +39,7 @@ export default React.memo(function Header(props: StackHeaderProps) {
|
||||
return (
|
||||
<HeaderSegment
|
||||
{...options}
|
||||
insets={insets}
|
||||
layout={layout}
|
||||
scene={scene}
|
||||
title={title}
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
ViewStyle,
|
||||
} from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
import { Route } from '@react-navigation/core';
|
||||
import HeaderBackButton from './HeaderBackButton';
|
||||
import HeaderBackground from './HeaderBackground';
|
||||
import getStatusBarHeight from '../../utils/getStatusBarHeight';
|
||||
import memoize from '../../utils/memoize';
|
||||
import {
|
||||
Layout,
|
||||
@@ -29,6 +29,7 @@ export type Scene<T> = {
|
||||
type Props = StackHeaderOptions & {
|
||||
headerTitle: (props: StackHeaderTitleProps) => React.ReactNode;
|
||||
layout: Layout;
|
||||
insets: EdgeInsets;
|
||||
onGoBack?: () => void;
|
||||
title?: string;
|
||||
leftLabel?: string;
|
||||
@@ -57,7 +58,7 @@ const warnIfHeaderStylesDefined = (styles: { [key: string]: any }) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const getDefaultHeaderHeight = (layout: Layout) => {
|
||||
export const getDefaultHeaderHeight = (layout: Layout, insets: EdgeInsets) => {
|
||||
const isLandscape = layout.width > layout.height;
|
||||
|
||||
let headerHeight;
|
||||
@@ -75,7 +76,7 @@ export const getDefaultHeaderHeight = (layout: Layout) => {
|
||||
headerHeight = 64;
|
||||
}
|
||||
|
||||
return headerHeight + getStatusBarHeight(isLandscape);
|
||||
return headerHeight + insets.top;
|
||||
};
|
||||
|
||||
export default class HeaderSegment extends React.Component<Props, State> {
|
||||
@@ -135,6 +136,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
const {
|
||||
scene,
|
||||
layout,
|
||||
insets,
|
||||
title: currentTitle,
|
||||
leftLabel: previousTitle,
|
||||
onGoBack,
|
||||
@@ -142,8 +144,6 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
headerLeft: left = onGoBack
|
||||
? (props: StackHeaderLeftButtonProps) => <HeaderBackButton {...props} />
|
||||
: undefined,
|
||||
// @ts-ignore
|
||||
headerStatusBarHeight = getStatusBarHeight(layout.width > layout.height),
|
||||
headerTransparent,
|
||||
headerTintColor,
|
||||
headerBackground,
|
||||
@@ -182,7 +182,7 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
);
|
||||
|
||||
const {
|
||||
height = getDefaultHeaderHeight(layout),
|
||||
height = getDefaultHeaderHeight(layout, insets),
|
||||
minHeight,
|
||||
maxHeight,
|
||||
backgroundColor,
|
||||
@@ -306,15 +306,17 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
pointerEvents="box-none"
|
||||
style={[{ height, minHeight, maxHeight, opacity }]}
|
||||
>
|
||||
<View
|
||||
pointerEvents="none"
|
||||
style={{ height: headerStatusBarHeight }}
|
||||
/>
|
||||
<View pointerEvents="none" style={{ height: insets.top }} />
|
||||
<View pointerEvents="box-none" style={styles.content}>
|
||||
{leftButton ? (
|
||||
<Animated.View
|
||||
pointerEvents="box-none"
|
||||
style={[styles.left, leftButtonStyle, leftContainerStyle]}
|
||||
style={[
|
||||
styles.left,
|
||||
{ left: insets.left },
|
||||
leftButtonStyle,
|
||||
leftContainerStyle,
|
||||
]}
|
||||
>
|
||||
{leftButton}
|
||||
</Animated.View>
|
||||
@@ -341,7 +343,12 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
||||
{right ? (
|
||||
<Animated.View
|
||||
pointerEvents="box-none"
|
||||
style={[styles.right, rightButtonStyle, rightContainerStyle]}
|
||||
style={[
|
||||
styles.right,
|
||||
{ right: insets.right },
|
||||
rightButtonStyle,
|
||||
rightContainerStyle,
|
||||
]}
|
||||
>
|
||||
{right({ tintColor: headerTintColor })}
|
||||
</Animated.View>
|
||||
|
||||
@@ -671,6 +671,12 @@ export default class Card extends React.Component<Props> {
|
||||
layouts: {
|
||||
screen: layout,
|
||||
},
|
||||
insets: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
ViewProps,
|
||||
} from 'react-native';
|
||||
import Animated from 'react-native-reanimated';
|
||||
import { EdgeInsets } from 'react-native-safe-area-context';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import * as Screens from 'react-native-screens'; // Import with * as to prevent getters being called
|
||||
import { Route } from '@react-navigation/core';
|
||||
@@ -36,6 +37,7 @@ type ProgressValues = {
|
||||
|
||||
type Props = {
|
||||
mode: 'card' | 'modal';
|
||||
insets: EdgeInsets;
|
||||
state: StackNavigationState;
|
||||
navigation: StackNavigationHelpers;
|
||||
descriptors: StackDescriptorMap;
|
||||
@@ -114,10 +116,11 @@ const FALLBACK_DESCRIPTOR = Object.freeze({ options: {} });
|
||||
|
||||
const getFloatingHeaderHeights = (
|
||||
routes: Route<string>[],
|
||||
insets: EdgeInsets,
|
||||
layout: Layout,
|
||||
previous: { [key: string]: number }
|
||||
) => {
|
||||
const defaultHeaderHeight = getDefaultHeaderHeight(layout);
|
||||
const defaultHeaderHeight = getDefaultHeaderHeight(layout, insets);
|
||||
|
||||
return routes.reduce(
|
||||
(acc, curr) => {
|
||||
@@ -201,6 +204,7 @@ export default class Stack extends React.Component<Props, State> {
|
||||
descriptors: props.descriptors,
|
||||
floatingHeaderHeights: getFloatingHeaderHeights(
|
||||
props.routes,
|
||||
props.insets,
|
||||
state.layout,
|
||||
state.floatingHeaderHeights
|
||||
),
|
||||
@@ -237,6 +241,7 @@ export default class Stack extends React.Component<Props, State> {
|
||||
layout,
|
||||
floatingHeaderHeights: getFloatingHeaderHeights(
|
||||
this.props.routes,
|
||||
this.props.insets,
|
||||
layout,
|
||||
{}
|
||||
),
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { Platform } from 'react-native';
|
||||
import {
|
||||
SafeAreaProvider,
|
||||
SafeAreaConsumer,
|
||||
EdgeInsets,
|
||||
} from 'react-native-safe-area-context';
|
||||
import { Route } from '@react-navigation/core';
|
||||
import { StackActions, StackNavigationState } from '@react-navigation/routers';
|
||||
|
||||
@@ -282,27 +287,34 @@ class StackView extends React.Component<Props, State> {
|
||||
mode !== 'modal' && Platform.OS === 'ios' ? 'float' : 'screen';
|
||||
|
||||
return (
|
||||
<Stack
|
||||
mode={mode}
|
||||
getPreviousRoute={this.getPreviousRoute}
|
||||
getGesturesEnabled={this.getGesturesEnabled}
|
||||
routes={routes}
|
||||
openingRoutes={opening}
|
||||
closingRoutes={closing}
|
||||
onGoBack={this.handleGoBack}
|
||||
onOpenRoute={this.handleOpenRoute}
|
||||
onCloseRoute={this.handleCloseRoute}
|
||||
onPageChangeStart={onPageChangeStart}
|
||||
onPageChangeConfirm={onPageChangeConfirm}
|
||||
onPageChangeCancel={onPageChangeCancel}
|
||||
renderHeader={this.renderHeader}
|
||||
renderScene={this.renderScene}
|
||||
headerMode={headerMode}
|
||||
state={state}
|
||||
navigation={navigation}
|
||||
descriptors={descriptors}
|
||||
{...rest}
|
||||
/>
|
||||
<SafeAreaProvider>
|
||||
<SafeAreaConsumer>
|
||||
{insets => (
|
||||
<Stack
|
||||
mode={mode}
|
||||
insets={insets as EdgeInsets}
|
||||
getPreviousRoute={this.getPreviousRoute}
|
||||
getGesturesEnabled={this.getGesturesEnabled}
|
||||
routes={routes}
|
||||
openingRoutes={opening}
|
||||
closingRoutes={closing}
|
||||
onGoBack={this.handleGoBack}
|
||||
onOpenRoute={this.handleOpenRoute}
|
||||
onCloseRoute={this.handleCloseRoute}
|
||||
onPageChangeStart={onPageChangeStart}
|
||||
onPageChangeConfirm={onPageChangeConfirm}
|
||||
onPageChangeCancel={onPageChangeCancel}
|
||||
renderHeader={this.renderHeader}
|
||||
renderScene={this.renderScene}
|
||||
headerMode={headerMode}
|
||||
state={state}
|
||||
navigation={navigation}
|
||||
descriptors={descriptors}
|
||||
{...rest}
|
||||
/>
|
||||
)}
|
||||
</SafeAreaConsumer>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user