mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-28 20:35:19 +08:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a322a6f6d5 | ||
|
|
efa53aab44 | ||
|
|
3eeea48fa3 | ||
|
|
3039ce1a5f | ||
|
|
cbe46d7303 | ||
|
|
11a99c8aaf | ||
|
|
6b5100c335 | ||
|
|
34dd1fe490 | ||
|
|
0cc9070dcd | ||
|
|
e369c89b81 | ||
|
|
99bf123ff2 | ||
|
|
feb93411bc | ||
|
|
86f07175fb | ||
|
|
8288853e3c | ||
|
|
c4bd2db542 | ||
|
|
ee40dd7d24 | ||
|
|
18a48105c2 | ||
|
|
fbac47b696 | ||
|
|
9aab47dac2 | ||
|
|
67309c00a6 | ||
|
|
86a724cfe3 | ||
|
|
eb78128439 | ||
|
|
c39ec7a10c | ||
|
|
0ff3347e97 |
@@ -11,7 +11,7 @@
|
|||||||
"splash": {
|
"splash": {
|
||||||
"image": "./assets/icons/splash.png"
|
"image": "./assets/icons/splash.png"
|
||||||
},
|
},
|
||||||
"sdkVersion": "25.0.0",
|
"sdkVersion": "26.0.0",
|
||||||
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||||
"packagerOpts": {
|
"packagerOpts": {
|
||||||
"assetExts": [
|
"assetExts": [
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import SimpleStack from './SimpleStack';
|
|||||||
import StackWithHeaderPreset from './StackWithHeaderPreset';
|
import StackWithHeaderPreset from './StackWithHeaderPreset';
|
||||||
import StackWithTranslucentHeader from './StackWithTranslucentHeader';
|
import StackWithTranslucentHeader from './StackWithTranslucentHeader';
|
||||||
import SimpleTabs from './SimpleTabs';
|
import SimpleTabs from './SimpleTabs';
|
||||||
|
import CustomTabNavigator from './CustomTabNavigator';
|
||||||
import TabAnimations from './TabAnimations';
|
import TabAnimations from './TabAnimations';
|
||||||
import TabsWithNavigationFocus from './TabsWithNavigationFocus';
|
import TabsWithNavigationFocus from './TabsWithNavigationFocus';
|
||||||
|
|
||||||
@@ -72,9 +73,13 @@ const ExampleInfo = {
|
|||||||
name: 'Drawer + Tabs Example',
|
name: 'Drawer + Tabs Example',
|
||||||
description: 'A drawer combined with tabs',
|
description: 'A drawer combined with tabs',
|
||||||
},
|
},
|
||||||
|
CustomTabNavigator: {
|
||||||
|
name: 'Custom Tab Navigator Example',
|
||||||
|
description: 'Extending the tab navigator',
|
||||||
|
},
|
||||||
CustomTabs: {
|
CustomTabs: {
|
||||||
name: 'Custom Tabs',
|
name: 'Custom Tabs View',
|
||||||
description: 'Custom tabs with tab router',
|
description: 'Custom tabs using TabRouter',
|
||||||
},
|
},
|
||||||
CustomTransitioner: {
|
CustomTransitioner: {
|
||||||
name: 'Custom Transitioner',
|
name: 'Custom Transitioner',
|
||||||
@@ -137,6 +142,7 @@ const ExampleRoutes = {
|
|||||||
StacksWithKeys,
|
StacksWithKeys,
|
||||||
StacksInTabs,
|
StacksInTabs,
|
||||||
StacksOverTabs,
|
StacksOverTabs,
|
||||||
|
CustomTabNavigator,
|
||||||
LinkStack: {
|
LinkStack: {
|
||||||
screen: SimpleStack,
|
screen: SimpleStack,
|
||||||
path: 'people/Jordan',
|
path: 'people/Jordan',
|
||||||
|
|||||||
201
examples/NavigationPlayground/js/CustomTabNavigator.js
Normal file
201
examples/NavigationPlayground/js/CustomTabNavigator.js
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/**
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
NavigationScreenProp,
|
||||||
|
NavigationEventSubscription,
|
||||||
|
} from 'react-navigation';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Platform,
|
||||||
|
ScrollView,
|
||||||
|
StatusBar,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
StyleSheet,
|
||||||
|
TouchableOpacity,
|
||||||
|
} from 'react-native';
|
||||||
|
import { SafeAreaView, TabNavigator } from 'react-navigation';
|
||||||
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||||
|
import SampleText from './SampleText';
|
||||||
|
|
||||||
|
const MyNavScreen = ({ navigation, banner }) => (
|
||||||
|
<SafeAreaView forceInset={{ horizontal: 'always', top: 'always' }}>
|
||||||
|
<SampleText>{banner}</SampleText>
|
||||||
|
<Button
|
||||||
|
onPress={() => navigation.navigate('Home')}
|
||||||
|
title="Go to home tab"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onPress={() => navigation.navigate('Settings')}
|
||||||
|
title="Go to settings tab"
|
||||||
|
/>
|
||||||
|
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||||
|
<StatusBar barStyle="default" />
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
|
||||||
|
const MyHomeScreen = ({ navigation }) => (
|
||||||
|
<MyNavScreen banner="Home Tab" navigation={navigation} />
|
||||||
|
);
|
||||||
|
|
||||||
|
MyHomeScreen.navigationOptions = {
|
||||||
|
tabBarTestIDProps: {
|
||||||
|
testID: 'TEST_ID_HOME',
|
||||||
|
accessibilityLabel: 'TEST_ID_HOME_ACLBL',
|
||||||
|
},
|
||||||
|
tabBarLabel: 'Home',
|
||||||
|
tabBarIcon: ({ tintColor, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
name={focused ? 'ios-home' : 'ios-home-outline'}
|
||||||
|
size={26}
|
||||||
|
style={{ color: tintColor }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
type MyPeopleScreenProps = {
|
||||||
|
navigation: NavigationScreenProp<*>,
|
||||||
|
};
|
||||||
|
class MyPeopleScreen extends React.Component<MyPeopleScreenProps> {
|
||||||
|
static navigationOptions = {
|
||||||
|
tabBarLabel: 'People',
|
||||||
|
tabBarIcon: ({ tintColor, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
name={focused ? 'ios-people' : 'ios-people-outline'}
|
||||||
|
size={26}
|
||||||
|
style={{ color: tintColor }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
render() {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
return <MyNavScreen banner="People Tab" navigation={navigation} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MyChatScreenProps = {
|
||||||
|
navigation: NavigationScreenProp<*>,
|
||||||
|
};
|
||||||
|
class MyChatScreen extends React.Component<MyChatScreenProps> {
|
||||||
|
static navigationOptions = {
|
||||||
|
tabBarLabel: 'Chat',
|
||||||
|
tabBarIcon: ({ tintColor, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
name={focused ? 'ios-chatboxes' : 'ios-chatboxes-outline'}
|
||||||
|
size={26}
|
||||||
|
style={{ color: tintColor }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
render() {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
return <MyNavScreen banner="Chat Tab" navigation={navigation} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MySettingsScreen = ({ navigation }) => (
|
||||||
|
<MyNavScreen banner="Settings Tab" navigation={navigation} />
|
||||||
|
);
|
||||||
|
|
||||||
|
MySettingsScreen.navigationOptions = {
|
||||||
|
tabBarLabel: 'Settings',
|
||||||
|
tabBarIcon: ({ tintColor, focused }) => (
|
||||||
|
<Ionicons
|
||||||
|
name={focused ? 'ios-settings' : 'ios-settings-outline'}
|
||||||
|
size={26}
|
||||||
|
style={{ color: tintColor }}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const SimpleTabs = TabNavigator(
|
||||||
|
{
|
||||||
|
Home: {
|
||||||
|
screen: MyHomeScreen,
|
||||||
|
},
|
||||||
|
People: {
|
||||||
|
screen: MyPeopleScreen,
|
||||||
|
},
|
||||||
|
Chat: {
|
||||||
|
screen: MyChatScreen,
|
||||||
|
},
|
||||||
|
Settings: {
|
||||||
|
screen: MySettingsScreen,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
navigationOptions: {
|
||||||
|
tabBarVisible: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
type SimpleTabsContainerProps = {
|
||||||
|
navigation: NavigationScreenProp<*>,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TabBarButton = ({ name, navigation }) => {
|
||||||
|
const currentName = navigation.state.routes[navigation.state.index].routeName;
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => {
|
||||||
|
navigation.navigate(name);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{ color: currentName === name ? 'blue' : 'black', fontSize: 32 }}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CustomTabBar extends React.Component<*> {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
height: 40,
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TabBarButton navigation={this.props.navigation} name="Home" />
|
||||||
|
<TabBarButton navigation={this.props.navigation} name="People" />
|
||||||
|
<TabBarButton navigation={this.props.navigation} name="Chat" />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleTabsContainer extends React.Component<SimpleTabsContainerProps> {
|
||||||
|
static router = {
|
||||||
|
...SimpleTabs.router,
|
||||||
|
getStateForAction(action, lastState) {
|
||||||
|
// You can override the behavior navigation actions here, which are dispatched via navigation.dispatch, or via helpers like navigaiton.navigate.
|
||||||
|
|
||||||
|
// In this case we simply use the default behavior:
|
||||||
|
const newState = SimpleTabs.router.getStateForAction(action, lastState);
|
||||||
|
|
||||||
|
console.log('Tab router action:', action, newState);
|
||||||
|
return newState;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1 }}>
|
||||||
|
<SimpleTabs navigation={this.props.navigation} />
|
||||||
|
<CustomTabBar navigation={this.props.navigation} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SimpleTabsContainer;
|
||||||
@@ -52,11 +52,6 @@ type MyPeopleScreenProps = {
|
|||||||
navigation: NavigationScreenProp<*>,
|
navigation: NavigationScreenProp<*>,
|
||||||
};
|
};
|
||||||
class MyPeopleScreen extends React.Component<MyPeopleScreenProps> {
|
class MyPeopleScreen extends React.Component<MyPeopleScreenProps> {
|
||||||
_s0: NavigationEventSubscription;
|
|
||||||
_s1: NavigationEventSubscription;
|
|
||||||
_s2: NavigationEventSubscription;
|
|
||||||
_s3: NavigationEventSubscription;
|
|
||||||
|
|
||||||
static navigationOptions = {
|
static navigationOptions = {
|
||||||
tabBarLabel: 'People',
|
tabBarLabel: 'People',
|
||||||
tabBarIcon: ({ tintColor, focused }) => (
|
tabBarIcon: ({ tintColor, focused }) => (
|
||||||
@@ -67,21 +62,6 @@ class MyPeopleScreen extends React.Component<MyPeopleScreenProps> {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
componentDidMount() {
|
|
||||||
this._s0 = this.props.navigation.addListener('willFocus', this._onEvent);
|
|
||||||
this._s1 = this.props.navigation.addListener('didFocus', this._onEvent);
|
|
||||||
this._s2 = this.props.navigation.addListener('willBlur', this._onEvent);
|
|
||||||
this._s3 = this.props.navigation.addListener('didBlur', this._onEvent);
|
|
||||||
}
|
|
||||||
componentWillUnmount() {
|
|
||||||
this._s0.remove();
|
|
||||||
this._s1.remove();
|
|
||||||
this._s2.remove();
|
|
||||||
this._s3.remove();
|
|
||||||
}
|
|
||||||
_onEvent = a => {
|
|
||||||
console.log('EVENT ON PEOPLE TAB', a.type, a);
|
|
||||||
};
|
|
||||||
render() {
|
render() {
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
return <MyNavScreen banner="People Tab" navigation={navigation} />;
|
return <MyNavScreen banner="People Tab" navigation={navigation} />;
|
||||||
@@ -92,11 +72,6 @@ type MyChatScreenProps = {
|
|||||||
navigation: NavigationScreenProp<*>,
|
navigation: NavigationScreenProp<*>,
|
||||||
};
|
};
|
||||||
class MyChatScreen extends React.Component<MyChatScreenProps> {
|
class MyChatScreen extends React.Component<MyChatScreenProps> {
|
||||||
_s0: NavigationEventSubscription;
|
|
||||||
_s1: NavigationEventSubscription;
|
|
||||||
_s2: NavigationEventSubscription;
|
|
||||||
_s3: NavigationEventSubscription;
|
|
||||||
|
|
||||||
static navigationOptions = {
|
static navigationOptions = {
|
||||||
tabBarLabel: 'Chat',
|
tabBarLabel: 'Chat',
|
||||||
tabBarIcon: ({ tintColor, focused }) => (
|
tabBarIcon: ({ tintColor, focused }) => (
|
||||||
@@ -107,21 +82,6 @@ class MyChatScreen extends React.Component<MyChatScreenProps> {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
componentDidMount() {
|
|
||||||
this._s0 = this.props.navigation.addListener('willFocus', this._onEvent);
|
|
||||||
this._s1 = this.props.navigation.addListener('didFocus', this._onEvent);
|
|
||||||
this._s2 = this.props.navigation.addListener('willBlur', this._onEvent);
|
|
||||||
this._s3 = this.props.navigation.addListener('didBlur', this._onEvent);
|
|
||||||
}
|
|
||||||
componentWillUnmount() {
|
|
||||||
this._s0.remove();
|
|
||||||
this._s1.remove();
|
|
||||||
this._s2.remove();
|
|
||||||
this._s3.remove();
|
|
||||||
}
|
|
||||||
_onEvent = a => {
|
|
||||||
console.log('EVENT ON CHAT TAB', a.type, a);
|
|
||||||
};
|
|
||||||
render() {
|
render() {
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
return <MyNavScreen banner="Chat Tab" navigation={navigation} />;
|
return <MyNavScreen banner="Chat Tab" navigation={navigation} />;
|
||||||
@@ -171,35 +131,4 @@ const SimpleTabs = TabNavigator(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
type SimpleTabsContainerProps = {
|
export default SimpleTabs;
|
||||||
navigation: NavigationScreenProp<*>,
|
|
||||||
};
|
|
||||||
|
|
||||||
class SimpleTabsContainer extends React.Component<SimpleTabsContainerProps> {
|
|
||||||
static router = SimpleTabs.router;
|
|
||||||
_s0: NavigationEventSubscription;
|
|
||||||
_s1: NavigationEventSubscription;
|
|
||||||
_s2: NavigationEventSubscription;
|
|
||||||
_s3: NavigationEventSubscription;
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this._s0 = this.props.navigation.addListener('willFocus', this._onAction);
|
|
||||||
this._s1 = this.props.navigation.addListener('didFocus', this._onAction);
|
|
||||||
this._s2 = this.props.navigation.addListener('willBlur', this._onAction);
|
|
||||||
this._s3 = this.props.navigation.addListener('didBlur', this._onAction);
|
|
||||||
}
|
|
||||||
componentWillUnmount() {
|
|
||||||
this._s0.remove();
|
|
||||||
this._s1.remove();
|
|
||||||
this._s2.remove();
|
|
||||||
this._s3.remove();
|
|
||||||
}
|
|
||||||
_onAction = a => {
|
|
||||||
console.log('TABS EVENT', a.type, a);
|
|
||||||
};
|
|
||||||
render() {
|
|
||||||
return <SimpleTabs navigation={this.props.navigation} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SimpleTabsContainer;
|
|
||||||
|
|||||||
@@ -119,6 +119,9 @@ const StacksInTabs = TabNavigator(
|
|||||||
tabBarPosition: 'bottom',
|
tabBarPosition: 'bottom',
|
||||||
animationEnabled: false,
|
animationEnabled: false,
|
||||||
swipeEnabled: false,
|
swipeEnabled: false,
|
||||||
|
tabBarOptions: {
|
||||||
|
showLabel: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,12 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button, SafeAreaView, Text } from 'react-native';
|
import { Button, SafeAreaView, Text } from 'react-native';
|
||||||
import { TabNavigator, withNavigationFocus } from 'react-navigation';
|
import {
|
||||||
|
TabNavigator,
|
||||||
|
TabBarTop,
|
||||||
|
StackNavigator,
|
||||||
|
withNavigationFocus,
|
||||||
|
} from 'react-navigation';
|
||||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
|
|
||||||
import SampleText from './SampleText';
|
import SampleText from './SampleText';
|
||||||
@@ -92,10 +97,35 @@ const TabsWithNavigationFocus = TabNavigator(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tabBarPosition: 'bottom',
|
tabBarComponent: TabBarTop,
|
||||||
|
tabBarPosition: 'top',
|
||||||
animationEnabled: true,
|
animationEnabled: true,
|
||||||
swipeEnabled: true,
|
swipeEnabled: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default TabsWithNavigationFocus;
|
const Stack = StackNavigator(
|
||||||
|
{
|
||||||
|
TabsWithNavigationFocus,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
navigationOptions: {
|
||||||
|
headerTitle: 'Navigation focus example',
|
||||||
|
headerLeft: null,
|
||||||
|
headerTitleStyle: {
|
||||||
|
flex: 1,
|
||||||
|
textAlign: 'left',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
},
|
||||||
|
headerTintColor: '#fff',
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: '#2196f3',
|
||||||
|
borderBottomWidth: 0,
|
||||||
|
elevation: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Stack;
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
"test": "node node_modules/jest/bin/jest.js && flow"
|
"test": "node node_modules/jest/bin/jest.js && flow"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"expo": "^25.0.0",
|
"expo": "^26.0.0",
|
||||||
"react": "16.2.0",
|
"react": "16.3.0-alpha.1",
|
||||||
"react-native": "^0.52.0",
|
"react-native": "^0.54.0",
|
||||||
"react-native-iphone-x-helper": "^1.0.2",
|
"react-native-iphone-x-helper": "^1.0.2",
|
||||||
"react-navigation": "link:../.."
|
"react-navigation": "link:../.."
|
||||||
},
|
},
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
"babel-plugin-transform-remove-console": "^6.9.0",
|
"babel-plugin-transform-remove-console": "^6.9.0",
|
||||||
"flow-bin": "^0.61.0",
|
"flow-bin": "^0.61.0",
|
||||||
"jest": "^21.0.1",
|
"jest": "^21.0.1",
|
||||||
"jest-expo": "^25.1.0",
|
"jest-expo": "^26.0.0",
|
||||||
"react-native-scripts": "^1.5.0",
|
"react-native-scripts": "^1.5.0",
|
||||||
"react-test-renderer": "16.0.0"
|
"react-test-renderer": "16.3.0-alpha.1"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"preset": "jest-expo",
|
"preset": "jest-expo",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-navigation",
|
"name": "react-navigation",
|
||||||
"version": "1.5.2",
|
"version": "1.5.11",
|
||||||
"description": "Routing and navigation for your React Native apps",
|
"description": "Routing and navigation for your React Native apps",
|
||||||
"main": "src/react-navigation.js",
|
"main": "src/react-navigation.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -32,9 +32,10 @@
|
|||||||
"hoist-non-react-statics": "^2.2.0",
|
"hoist-non-react-statics": "^2.2.0",
|
||||||
"path-to-regexp": "^1.7.0",
|
"path-to-regexp": "^1.7.0",
|
||||||
"prop-types": "^15.5.10",
|
"prop-types": "^15.5.10",
|
||||||
|
"react-lifecycles-compat": "^1.0.2",
|
||||||
"react-native-drawer-layout-polyfill": "^1.3.2",
|
"react-native-drawer-layout-polyfill": "^1.3.2",
|
||||||
"react-native-safe-area-view": "^0.7.0",
|
"react-native-safe-area-view": "^0.7.0",
|
||||||
"react-native-tab-view": "^0.0.74"
|
"react-native-tab-view": "github:react-navigation/react-native-tab-view"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.24.1",
|
"babel-cli": "^6.24.1",
|
||||||
|
|||||||
@@ -137,9 +137,15 @@ exports[`TabNavigator renders successfully 1`] = `
|
|||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={
|
style={
|
||||||
Object {
|
Array [
|
||||||
"flexGrow": 1,
|
Object {
|
||||||
}
|
"height": 29,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
Object {
|
||||||
|
"flexGrow": 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ export default (routeConfigs, config = {}) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getNextState(prevState, possibleNextState) {
|
getNextState(prevState, possibleNextState) {
|
||||||
|
if (!prevState) {
|
||||||
|
return possibleNextState;
|
||||||
|
}
|
||||||
|
|
||||||
let nextState;
|
let nextState;
|
||||||
if (prevState.index !== possibleNextState.index && resetOnBlur) {
|
if (prevState.index !== possibleNextState.index && resetOnBlur) {
|
||||||
const prevRouteName = prevState.routes[prevState.index].routeName;
|
const prevRouteName = prevState.routes[prevState.index].routeName;
|
||||||
|
|||||||
@@ -25,6 +25,20 @@ describe('SwitchRouter', () => {
|
|||||||
expect(state3.routes[0].routes.length).toEqual(1);
|
expect(state3.routes[0].routes.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('sets the next state even if no previous state is provided', () => {
|
||||||
|
const router = getExampleRouter();
|
||||||
|
const initialState = router.getStateForAction({
|
||||||
|
type: NavigationActions.INIT,
|
||||||
|
});
|
||||||
|
const nextState = router.getStateForAction({
|
||||||
|
type: NavigationActions.NAVIGATE,
|
||||||
|
routeName: 'A2',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(nextState.routes[0].index).toEqual(1);
|
||||||
|
expect(nextState.routes[0].routes.length).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
test('does not reset the route on unfocus if resetOnBlur is false', () => {
|
test('does not reset the route on unfocus if resetOnBlur is false', () => {
|
||||||
const router = getExampleRouter({ resetOnBlur: false });
|
const router = getExampleRouter({ resetOnBlur: false });
|
||||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ class CardStack extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_isRouteFocused = route => {
|
_isRouteFocused = route => {
|
||||||
const { state } = this.props.navigation;
|
const { transitionProps: { navigation: { state } } } = this.props;
|
||||||
const focusedRoute = state.routes[state.index];
|
const focusedRoute = state.routes[state.index];
|
||||||
return route === focusedRoute;
|
return route === focusedRoute;
|
||||||
};
|
};
|
||||||
@@ -129,7 +129,7 @@ class CardStack extends React.Component {
|
|||||||
const screenNavigation = addNavigationHelpers({
|
const screenNavigation = addNavigationHelpers({
|
||||||
dispatch: navigation.dispatch,
|
dispatch: navigation.dispatch,
|
||||||
state: scene.route,
|
state: scene.route,
|
||||||
isFocused: this._isRouteFocused.bind(this, scene.route),
|
isFocused: () => this._isRouteFocused(scene.route),
|
||||||
addListener: this._childEventSubscribers[scene.route.key],
|
addListener: this._childEventSubscribers[scene.route.key],
|
||||||
});
|
});
|
||||||
screenDetails = {
|
screenDetails = {
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export default class DrawerView extends React.PureComponent {
|
|||||||
this._screenNavigationProp = addNavigationHelpers({
|
this._screenNavigationProp = addNavigationHelpers({
|
||||||
dispatch: navigation.dispatch,
|
dispatch: navigation.dispatch,
|
||||||
state: navigationState,
|
state: navigationState,
|
||||||
isFocused: this._isRouteFocused.bind(this, navigationState),
|
isFocused: () => this._isRouteFocused(navigationState),
|
||||||
addListener: this._childEventSubscribers[navigationState.key],
|
addListener: this._childEventSubscribers[navigationState.key],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,40 +1,33 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Platform, StyleSheet, View } from 'react-native';
|
import { Platform, StyleSheet, View } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import withLifecyclePolyfill from 'react-lifecycles-compat';
|
||||||
|
|
||||||
import SceneView from './SceneView';
|
import SceneView from './SceneView';
|
||||||
|
|
||||||
const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view out of its container
|
const FAR_FAR_AWAY = 3000; // this should be big enough to move the whole view out of its container
|
||||||
|
|
||||||
export default class ResourceSavingSceneView extends React.PureComponent {
|
class ResourceSavingSceneView extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
const key = props.childNavigation.state.key;
|
|
||||||
const focusedIndex = props.navigation.state.index;
|
|
||||||
const focusedKey = props.navigation.state.routes[focusedIndex].key;
|
|
||||||
const isFocused = key === focusedKey;
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
awake: props.lazy ? isFocused : true,
|
awake: props.lazy ? props.isFocused : true,
|
||||||
visible: isFocused,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
static getDerivedStateFromProps(nextProps, prevState) {
|
||||||
this._actionListener = this.props.navigation.addListener(
|
if (nextProps.isFocused && !prevState.awake) {
|
||||||
'action',
|
return { awake: true };
|
||||||
this._onAction
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
return null;
|
||||||
this._actionListener.remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { awake, visible } = this.state;
|
const { awake } = this.state;
|
||||||
const {
|
const {
|
||||||
|
isFocused,
|
||||||
childNavigation,
|
childNavigation,
|
||||||
navigation,
|
navigation,
|
||||||
removeClippedSubviews,
|
removeClippedSubviews,
|
||||||
@@ -49,12 +42,12 @@ export default class ResourceSavingSceneView extends React.PureComponent {
|
|||||||
removeClippedSubviews={
|
removeClippedSubviews={
|
||||||
Platform.OS === 'android'
|
Platform.OS === 'android'
|
||||||
? removeClippedSubviews
|
? removeClippedSubviews
|
||||||
: !visible && removeClippedSubviews
|
: !isFocused && removeClippedSubviews
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={
|
style={
|
||||||
this._mustAlwaysBeVisible() || visible
|
this._mustAlwaysBeVisible() || isFocused
|
||||||
? styles.innerAttached
|
? styles.innerAttached
|
||||||
: styles.innerDetached
|
: styles.innerDetached
|
||||||
}
|
}
|
||||||
@@ -68,33 +61,6 @@ export default class ResourceSavingSceneView extends React.PureComponent {
|
|||||||
_mustAlwaysBeVisible = () => {
|
_mustAlwaysBeVisible = () => {
|
||||||
return this.props.animationEnabled || this.props.swipeEnabled;
|
return this.props.animationEnabled || this.props.swipeEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
_onAction = payload => {
|
|
||||||
// We do not care about transition complete events, they won't actually change the state
|
|
||||||
if (
|
|
||||||
payload.action.type == 'Navigation/COMPLETE_TRANSITION' ||
|
|
||||||
!payload.state
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { routes, index } = payload.state;
|
|
||||||
const key = this.props.childNavigation.state.key;
|
|
||||||
|
|
||||||
if (routes[index].key === key) {
|
|
||||||
if (!this.state.visible) {
|
|
||||||
let nextState = { visible: true };
|
|
||||||
if (!this.state.awake) {
|
|
||||||
nextState.awake = true;
|
|
||||||
}
|
|
||||||
this.setState(nextState);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.state.visible) {
|
|
||||||
this.setState({ visible: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
@@ -110,3 +76,5 @@ const styles = StyleSheet.create({
|
|||||||
top: FAR_FAR_AWAY,
|
top: FAR_FAR_AWAY,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default withLifecyclePolyfill(ResourceSavingSceneView);
|
||||||
|
|||||||
@@ -101,6 +101,8 @@ class TabBarBottom extends React.PureComponent {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const horizontal = this._shouldUseHorizontalTabs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TabBarIcon
|
<TabBarIcon
|
||||||
position={position}
|
position={position}
|
||||||
@@ -109,11 +111,11 @@ class TabBarBottom extends React.PureComponent {
|
|||||||
inactiveTintColor={inactiveTintColor}
|
inactiveTintColor={inactiveTintColor}
|
||||||
renderIcon={renderIcon}
|
renderIcon={renderIcon}
|
||||||
scene={scene}
|
scene={scene}
|
||||||
style={
|
style={[
|
||||||
showLabel && this._shouldUseHorizontalTabs()
|
styles.iconWithExplicitHeight,
|
||||||
? styles.horizontalIcon
|
showLabel === false && !horizontal && styles.iconWithoutLabel,
|
||||||
: styles.icon
|
showLabel !== false && !horizontal && styles.iconWithLabel,
|
||||||
}
|
]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -319,10 +321,13 @@ const styles = StyleSheet.create({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
},
|
},
|
||||||
icon: {
|
iconWithoutLabel: {
|
||||||
flexGrow: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
horizontalIcon: {
|
iconWithLabel: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
iconWithExplicitHeight: {
|
||||||
height: Platform.isPad ? DEFAULT_HEIGHT : COMPACT_HEIGHT,
|
height: Platform.isPad ? DEFAULT_HEIGHT : COMPACT_HEIGHT,
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
|
|||||||
@@ -54,11 +54,12 @@ const styles = StyleSheet.create({
|
|||||||
// We render the icon twice at the same position on top of each other:
|
// We render the icon twice at the same position on top of each other:
|
||||||
// active and inactive one, so we can fade between them:
|
// active and inactive one, so we can fade between them:
|
||||||
// Cover the whole iconContainer:
|
// Cover the whole iconContainer:
|
||||||
alignItems: 'center',
|
|
||||||
alignSelf: 'center',
|
|
||||||
height: '100%',
|
|
||||||
justifyContent: 'center',
|
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
alignSelf: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
minWidth: 30,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ class TabView extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_renderScene = ({ route }) => {
|
_renderScene = ({ route }) => {
|
||||||
const { screenProps } = this.props;
|
const { screenProps, navigation } = this.props;
|
||||||
|
const focusedIndex = navigation.state.index;
|
||||||
|
const focusedKey = navigation.state.routes[focusedIndex].key;
|
||||||
|
const key = route.key;
|
||||||
const childNavigation = this.props.childNavigationProps[route.key];
|
const childNavigation = this.props.childNavigationProps[route.key];
|
||||||
const TabComponent = this.props.router.getComponentForRouteName(
|
const TabComponent = this.props.router.getComponentForRouteName(
|
||||||
route.routeName
|
route.routeName
|
||||||
@@ -31,6 +34,7 @@ class TabView extends React.PureComponent {
|
|||||||
return (
|
return (
|
||||||
<ResourceSavingSceneView
|
<ResourceSavingSceneView
|
||||||
lazy={this.props.lazy}
|
lazy={this.props.lazy}
|
||||||
|
isFocused={focusedKey === key}
|
||||||
removeClippedSubViews={this.props.removeClippedSubviews}
|
removeClippedSubViews={this.props.removeClippedSubviews}
|
||||||
animationEnabled={this.props.animationEnabled}
|
animationEnabled={this.props.animationEnabled}
|
||||||
swipeEnabled={this.props.swipeEnabled}
|
swipeEnabled={this.props.swipeEnabled}
|
||||||
|
|||||||
@@ -83,9 +83,15 @@ exports[`TabBarBottom renders successfully 1`] = `
|
|||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={
|
style={
|
||||||
Object {
|
Array [
|
||||||
"flexGrow": 1,
|
Object {
|
||||||
}
|
"height": 29,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
Object {
|
||||||
|
"flexGrow": 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
|
|||||||
Reference in New Issue
Block a user