mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-28 20:35:19 +08:00
Use react-native-screens and keep inactive screens in memory, like with tabs
This commit is contained in:
committed by
satyajit.happy
parent
36893fd572
commit
f2eda6ce48
@@ -1,16 +1,36 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Dimensions } from 'react-native';
|
import { Dimensions, StyleSheet } from 'react-native';
|
||||||
import { SceneView } from '@react-navigation/core';
|
import { SceneView } from '@react-navigation/core';
|
||||||
|
// eslint-disable-next-line import/no-unresolved
|
||||||
|
import { ScreenContainer } from 'react-native-screens';
|
||||||
|
|
||||||
import DrawerActions from '../routers/DrawerActions';
|
import DrawerActions from '../routers/DrawerActions';
|
||||||
import DrawerLayout from './DrawerLayout';
|
import DrawerLayout from './DrawerLayout';
|
||||||
import DrawerSidebar from './DrawerSidebar';
|
import DrawerSidebar from './DrawerSidebar';
|
||||||
import DrawerGestureContext from '../utils/DrawerGestureContext';
|
import DrawerGestureContext from '../utils/DrawerGestureContext';
|
||||||
|
import ResourceSavingScene from '../views/ResourceSavingScene';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that renders the drawer.
|
* Component that renders the drawer.
|
||||||
*/
|
*/
|
||||||
export default class DrawerView extends React.PureComponent {
|
export default class DrawerView extends React.PureComponent {
|
||||||
|
static defaultProps = {
|
||||||
|
lazy: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(nextProps, prevState) {
|
||||||
|
const { index } = nextProps.navigation.state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Set the current tab to be loaded if it was not loaded before
|
||||||
|
loaded: prevState.loaded.includes(index)
|
||||||
|
? prevState.loaded
|
||||||
|
: [...prevState.loaded, index],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
loaded: [this.props.navigation.state.index],
|
||||||
drawerWidth:
|
drawerWidth:
|
||||||
typeof this.props.navigationConfig.drawerWidth === 'function'
|
typeof this.props.navigationConfig.drawerWidth === 'function'
|
||||||
? this.props.navigationConfig.drawerWidth()
|
? this.props.navigationConfig.drawerWidth()
|
||||||
@@ -121,11 +141,12 @@ export default class DrawerView extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { state } = this.props.navigation;
|
const { lazy, navigation } = this.props;
|
||||||
const activeKey = state.routes[state.index].key;
|
const { loaded } = this.state;
|
||||||
const descriptor = this.props.descriptors[activeKey];
|
const { state } = navigation;
|
||||||
|
const { routes } = state;
|
||||||
const { drawerLockMode } = descriptor.options;
|
const activeKey = routes[state.index].key;
|
||||||
|
const { drawerLockMode } = this.props.descriptors[activeKey].options;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerLayout
|
<DrawerLayout
|
||||||
@@ -162,13 +183,42 @@ export default class DrawerView extends React.PureComponent {
|
|||||||
overlayColor={this.props.navigationConfig.overlayColor}
|
overlayColor={this.props.navigationConfig.overlayColor}
|
||||||
>
|
>
|
||||||
<DrawerGestureContext.Provider value={this.drawerGestureRef}>
|
<DrawerGestureContext.Provider value={this.drawerGestureRef}>
|
||||||
<SceneView
|
<ScreenContainer style={styles.pages}>
|
||||||
navigation={descriptor.navigation}
|
{routes.map((route, index) => {
|
||||||
screenProps={this.props.screenProps}
|
if (lazy && !loaded.includes(index)) {
|
||||||
component={descriptor.getComponent()}
|
// Don't render a screen if we've never navigated to it
|
||||||
/>
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isFocused = navigation.state.index === index;
|
||||||
|
const descriptor = this.props.descriptors[route.key];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ResourceSavingScene
|
||||||
|
key={route.key}
|
||||||
|
style={[
|
||||||
|
StyleSheet.absoluteFill,
|
||||||
|
{ opacity: isFocused ? 1 : 0 },
|
||||||
|
]}
|
||||||
|
isVisible={isFocused}
|
||||||
|
>
|
||||||
|
<SceneView
|
||||||
|
navigation={descriptor.navigation}
|
||||||
|
screenProps={this.props.screenProps}
|
||||||
|
component={descriptor.getComponent()}
|
||||||
|
/>
|
||||||
|
</ResourceSavingScene>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ScreenContainer>
|
||||||
</DrawerGestureContext.Provider>
|
</DrawerGestureContext.Provider>
|
||||||
</DrawerLayout>
|
</DrawerLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
pages: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
57
packages/drawer/src/views/ResourceSavingScene.js
Normal file
57
packages/drawer/src/views/ResourceSavingScene.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/* @flow */
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Platform, StyleSheet, View } from 'react-native';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-unresolved
|
||||||
|
import { Screen, screensEnabled } from 'react-native-screens';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isVisible: boolean,
|
||||||
|
children: React.Node,
|
||||||
|
style?: any,
|
||||||
|
};
|
||||||
|
|
||||||
|
const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view out of its container
|
||||||
|
|
||||||
|
export default class ResourceSavingScene extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
if (screensEnabled && screensEnabled()) {
|
||||||
|
const { isVisible, ...rest } = this.props;
|
||||||
|
return <Screen active={isVisible ? 1 : 0} {...rest} />;
|
||||||
|
}
|
||||||
|
const { isVisible, children, style, ...rest } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[styles.container, style]}
|
||||||
|
collapsable={false}
|
||||||
|
removeClippedSubviews={
|
||||||
|
// On iOS, set removeClippedSubviews to true only when not focused
|
||||||
|
// This is an workaround for a bug where the clipped view never re-appears
|
||||||
|
Platform.OS === 'ios' ? !isVisible : true
|
||||||
|
}
|
||||||
|
pointerEvents={isVisible ? 'auto' : 'none'}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<View style={isVisible ? styles.attached : styles.detached}>
|
||||||
|
{children}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
attached: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
detached: {
|
||||||
|
flex: 1,
|
||||||
|
top: FAR_FAR_AWAY,
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user