mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-23 04:18:18 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6373b802dd | ||
|
|
138151433d | ||
|
|
2744cb32b7 |
@@ -114,10 +114,10 @@ const ExampleInfo = {
|
||||
name: 'Animated Tabs Example',
|
||||
description: 'Tab transitions have custom animations',
|
||||
},
|
||||
// TabsWithNavigationFocus: {
|
||||
// name: 'withNavigationFocus',
|
||||
// description: 'Receive the focus prop to know when a screen is focused',
|
||||
// },
|
||||
TabsWithNavigationFocus: {
|
||||
name: 'withNavigationFocus',
|
||||
description: 'Receive the focus prop to know when a screen is focused',
|
||||
},
|
||||
};
|
||||
|
||||
const ExampleRoutes = {
|
||||
@@ -146,7 +146,7 @@ const ExampleRoutes = {
|
||||
path: 'settings',
|
||||
},
|
||||
TabAnimations,
|
||||
// TabsWithNavigationFocus: TabsWithNavigationFocus,
|
||||
TabsWithNavigationFocus,
|
||||
};
|
||||
|
||||
type State = {
|
||||
|
||||
@@ -3,40 +3,75 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { SafeAreaView, Text } from 'react-native';
|
||||
import { Button, SafeAreaView, Text } from 'react-native';
|
||||
import { TabNavigator, withNavigationFocus } from 'react-navigation';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
|
||||
import SampleText from './SampleText';
|
||||
|
||||
const createTabScreen = (name, icon, focusedIcon, tintColor = '#673ab7') => {
|
||||
const TabScreen = ({ isFocused }) => (
|
||||
<SafeAreaView
|
||||
forceInset={{ horizontal: 'always', top: 'always' }}
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontWeight: '700', fontSize: 16, marginBottom: 5 }}>
|
||||
{'Tab ' + name.toLowerCase()}
|
||||
class Child extends React.Component<any, any> {
|
||||
render() {
|
||||
return (
|
||||
<Text style={{ color: this.props.isFocused ? 'green' : 'maroon' }}>
|
||||
{this.props.isFocused
|
||||
? 'I know that my parent is focused!'
|
||||
: 'My parent is not focused! :O'}
|
||||
</Text>
|
||||
<Text>{'props.isFocused: ' + (isFocused ? ' true' : 'false')}</Text>
|
||||
</SafeAreaView>
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TabScreen.navigationOptions = {
|
||||
tabBarLabel: name,
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<MaterialCommunityIcons
|
||||
name={focused ? focusedIcon : icon}
|
||||
size={26}
|
||||
style={{ color: focused ? tintColor : '#ccc' }}
|
||||
/>
|
||||
),
|
||||
};
|
||||
const ChildWithNavigationFocus = withNavigationFocus(Child);
|
||||
|
||||
const createTabScreen = (name, icon, focusedIcon, tintColor = '#673ab7') => {
|
||||
class TabScreen extends React.Component<any, any> {
|
||||
static navigationOptions = {
|
||||
tabBarLabel: name,
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<MaterialCommunityIcons
|
||||
name={focused ? focusedIcon : icon}
|
||||
size={26}
|
||||
style={{ color: focused ? tintColor : '#ccc' }}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
state = { showChild: false };
|
||||
|
||||
render() {
|
||||
const { isFocused } = this.props;
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
forceInset={{ horizontal: 'always', top: 'always' }}
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontWeight: '700', fontSize: 16, marginBottom: 5 }}>
|
||||
{'Tab ' + name.toLowerCase()}
|
||||
</Text>
|
||||
<Text style={{ marginBottom: 20 }}>
|
||||
{'props.isFocused: ' + (isFocused ? ' true' : 'false')}
|
||||
</Text>
|
||||
{this.state.showChild ? (
|
||||
<ChildWithNavigationFocus />
|
||||
) : (
|
||||
<Button
|
||||
title="Press me"
|
||||
onPress={() => this.setState({ showChild: true })}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
onPress={() => this.props.navigation.goBack(null)}
|
||||
title="Back to other examples"
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
return withNavigationFocus(TabScreen);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-navigation",
|
||||
"version": "1.3.2",
|
||||
"version": "1.4.0",
|
||||
"description": "Routing and navigation for your React Native apps",
|
||||
"main": "src/react-navigation.js",
|
||||
"repository": {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Based on the 'action' events that get fired for this navigation state, this utility will fire
|
||||
* focus and blur events for this child
|
||||
*/
|
||||
|
||||
export default function getChildEventSubscriber(addListener, key) {
|
||||
const actionSubscribers = new Set();
|
||||
const willFocusSubscribers = new Set();
|
||||
|
||||
@@ -82,6 +82,8 @@ class CardStack extends React.Component {
|
||||
|
||||
_screenDetails = {};
|
||||
|
||||
_childEventSubscribers = {};
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
if (props.screenProps !== this.props.screenProps) {
|
||||
this._screenDetails = {};
|
||||
@@ -96,17 +98,39 @@ class CardStack extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const activeKeys = this.props.transitionProps.navigation.state.routes.map(
|
||||
route => route.key
|
||||
);
|
||||
Object.keys(this._childEventSubscribers).forEach(key => {
|
||||
if (!activeKeys.includes(key)) {
|
||||
delete this._childEventSubscribers[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_isRouteFocused = route => {
|
||||
const { state } = this.props.navigation;
|
||||
const focusedRoute = state.routes[state.index];
|
||||
return route === focusedRoute;
|
||||
};
|
||||
|
||||
_getScreenDetails = scene => {
|
||||
const { screenProps, transitionProps: { navigation }, router } = this.props;
|
||||
let screenDetails = this._screenDetails[scene.key];
|
||||
if (!screenDetails || screenDetails.state !== scene.route) {
|
||||
if (!this._childEventSubscribers[scene.route.key]) {
|
||||
this._childEventSubscribers[scene.route.key] = getChildEventSubscriber(
|
||||
navigation.addListener,
|
||||
scene.route.key
|
||||
);
|
||||
}
|
||||
|
||||
const screenNavigation = addNavigationHelpers({
|
||||
dispatch: navigation.dispatch,
|
||||
state: scene.route,
|
||||
addListener: getChildEventSubscriber(
|
||||
navigation.addListener,
|
||||
scene.route.key
|
||||
),
|
||||
isFocused: this._isRouteFocused.bind(this, scene.route),
|
||||
addListener: this._childEventSubscribers[scene.route.key],
|
||||
});
|
||||
screenDetails = {
|
||||
state: scene.route,
|
||||
|
||||
@@ -17,6 +17,8 @@ export default class DrawerView extends React.PureComponent {
|
||||
: this.props.drawerWidth,
|
||||
};
|
||||
|
||||
_childEventSubscribers = {};
|
||||
|
||||
componentWillMount() {
|
||||
this._updateScreenNavigation(this.props.navigation);
|
||||
|
||||
@@ -27,6 +29,17 @@ export default class DrawerView extends React.PureComponent {
|
||||
Dimensions.removeEventListener('change', this._updateWidth);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const activeKeys = this.props.navigation.state.routes.map(
|
||||
route => route.key
|
||||
);
|
||||
Object.keys(this._childEventSubscribers).forEach(key => {
|
||||
if (!activeKeys.includes(key)) {
|
||||
delete this._childEventSubscribers[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (
|
||||
this.props.navigation.state.index !== nextProps.navigation.state.index
|
||||
@@ -68,6 +81,12 @@ export default class DrawerView extends React.PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
_isRouteFocused = route => () => {
|
||||
const { state } = this.props.navigation;
|
||||
const focusedRoute = state.routes[state.index];
|
||||
return route === focusedRoute;
|
||||
};
|
||||
|
||||
_updateScreenNavigation = navigation => {
|
||||
const { drawerCloseRoute } = this.props;
|
||||
const navigationState = navigation.state.routes.find(
|
||||
@@ -79,13 +98,18 @@ export default class DrawerView extends React.PureComponent {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._childEventSubscribers[navigationState.key]) {
|
||||
this._childEventSubscribers[
|
||||
navigationState.key
|
||||
] = getChildEventSubscriber(navigation.addListener, navigationState.key);
|
||||
}
|
||||
|
||||
this._screenNavigationProp = addNavigationHelpers({
|
||||
dispatch: navigation.dispatch,
|
||||
state: navigationState,
|
||||
addListener: getChildEventSubscriber(
|
||||
navigation.addListener,
|
||||
navigationState.key
|
||||
),
|
||||
isFocused: this._isRouteFocused.bind(this, navigationState),
|
||||
addListener: this._childEventSubscribers[navigationState.key],
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -248,6 +248,7 @@ exports[`TabBarBottom renders successfully 1`] = `
|
||||
"dispatch": undefined,
|
||||
"getParam": [Function],
|
||||
"goBack": [Function],
|
||||
"isFocused": [Function],
|
||||
"navigate": [Function],
|
||||
"pop": [Function],
|
||||
"popToTop": [Function],
|
||||
|
||||
@@ -12,9 +12,13 @@ export default function withNavigationFocus(Component) {
|
||||
navigation: propTypes.object.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
isFocused: false,
|
||||
};
|
||||
constructor(props, context) {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
isFocused: this.getNavigation(props, context).isFocused(),
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const navigation = this.getNavigation();
|
||||
@@ -32,8 +36,8 @@ export default function withNavigationFocus(Component) {
|
||||
this.subscriptions.forEach(sub => sub.remove());
|
||||
}
|
||||
|
||||
getNavigation = () => {
|
||||
const navigation = this.props.navigation || this.context.navigation;
|
||||
getNavigation = (props = this.props, context = this.context) => {
|
||||
const navigation = props.navigation || context.navigation;
|
||||
invariant(
|
||||
!!navigation,
|
||||
'withNavigationFocus can only be used on a view hierarchy of a navigator. The wrapped component is unable to get access to navigation from props or context.'
|
||||
|
||||
@@ -10,6 +10,8 @@ export default function withCachedChildNavigation(Comp) {
|
||||
return class extends React.PureComponent {
|
||||
static displayName = `withCachedChildNavigation(${displayName})`;
|
||||
|
||||
_childEventSubscribers = {};
|
||||
|
||||
componentWillMount() {
|
||||
this._updateNavigationProps(this.props.navigation);
|
||||
}
|
||||
@@ -18,6 +20,23 @@ export default function withCachedChildNavigation(Comp) {
|
||||
this._updateNavigationProps(nextProps.navigation);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const activeKeys = this.props.navigation.state.routes.map(
|
||||
route => route.key
|
||||
);
|
||||
Object.keys(this._childEventSubscribers).forEach(key => {
|
||||
if (!activeKeys.includes(key)) {
|
||||
delete this._childEventSubscribers[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_isRouteFocused = route => () => {
|
||||
const { state } = this.props.navigation;
|
||||
const focusedRoute = state.routes[state.index];
|
||||
return route === focusedRoute;
|
||||
};
|
||||
|
||||
_updateNavigationProps = navigation => {
|
||||
// Update props for each child route
|
||||
if (!this._childNavigationProps) {
|
||||
@@ -28,13 +47,19 @@ export default function withCachedChildNavigation(Comp) {
|
||||
if (childNavigation && childNavigation.state === route) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._childEventSubscribers[route.key]) {
|
||||
this._childEventSubscribers[route.key] = getChildEventSubscriber(
|
||||
navigation.addListener,
|
||||
route.key
|
||||
);
|
||||
}
|
||||
|
||||
this._childNavigationProps[route.key] = addNavigationHelpers({
|
||||
dispatch: navigation.dispatch,
|
||||
state: route,
|
||||
addListener: getChildEventSubscriber(
|
||||
navigation.addListener,
|
||||
route.key
|
||||
),
|
||||
isFocused: this._isRouteFocused.bind(this, route),
|
||||
addListener: this._childEventSubscribers[route.key],
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user