Learn once, navigate anywhere.
React Navigation的诞生,源于React Native社区对基于Javascript的可扩展且使用简单的导航解决方案的需求
只需安装react-navigation的npm package, 就可以开始使用React Navigation了
安装react-navigation
- 使用 NPM 安装
npm install --save react-navigation
或者使用yarn安装
yarn add react-navigation
要开始使用React Navigation,您必须先创建一个navigator,React Navigation带有三种默认的navigator。
- StackNavigator - 为应用程序提供了一种页面切换的方法,每次切换时,新的页面会放置在堆栈的顶部
- TabNavigator - 用于设置具有多个Tab页的页面
- DrawerNavigator - 用于设置抽屉导航的页面
StackNavigator
'use strict';
import React,{Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
PixelRatio,
} from 'react-native';
//1. 导入文件
import { StackNavigator } from 'react-navigation';
//2. 编写页面
const HomeScreen = ({navigation}) =>(
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
//5. 从Home页面跳转到Details页面
<Button
onPress={()=>navigation.navigate('Details')}
title='Go to Details'
></Button>
</View>
);
const Details = ()=>(
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
//3.创建StackNavigator
const RootNavigator = StackNavigator({
Home:{
screen:HomeScreen,
//4. 添加标题
navigationOptions:{
headerTitle:'home',
},
},
Details:{
screen:Details,
navigationOptions:{
headerTitle:'details',
},
}
});
export default RootNavigator;
效果图


TabNavigator
我们将在例子中使用
react-native-vector-icons, 如果你的项目中没有安装,请自行安装。
react-native-vector-icons ICONS是矢量图,可以直接使用图片名, 就能加载图片的第三方,使用很方便, 你不需要在工程文件夹里塞各种图片, 节省很多空间,
图片库
图片库
icons 使用
代码
'use strict';
import React,{Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
PixelRatio,
} from 'react-native';
//1. 导入文件
import { createBottomTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
//2.创建一些页面
const HomeScreen=()=>(
<View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
<Text>HomeScreen</Text>
</View>
);
const ProfileScreen=()=>(
<View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
<Text>ProfileScreen</Text>
</View>
);
//3. 添加TabNavigator中
const RootTabs = createBottomTabNavigator({
Home:{
screen:HomeScreen,
navigationOptions:{
//4. 创建标签
tabBarLabel:'MyHome',
//5 .添加图标
tabBarIcon:({tintColor,focused})=>(
<Ionicons
name={focused?'ios-home' : 'md-home'}
size={26}
style={focused?{ color: tintColor }:{color:'#f00'}}
>
</Ionicons>
),
},
},
Profile:{
screen:ProfileScreen,
navigationOptions:{
tabBarLabel:'MyProfile',
tabBarIcon:({tintColor,focused})=>(
<Ionicons
name={'ios-aperture'}
size={26}
style={{color:tintColor}}
>
</Ionicons>
),
}
},
});
//最后导出
export default RootTabs;
效果图


出现的几个问题
- 消除警告
"Method jumpToIndex is deprecated. Please upgrade your code to use jumpTo instead. Change your code from jumpToIndex(1) to `jumpTo('Parties')."
这个警告的意思是把TabNavigator替换成createBottomTabNavigator
问题解决
import { createBottomTabNavigator } from 'react-navigation';
const RootTabs = createBottomTabNavigator({...});
- react-native-vector-icons 使用问题
- 安装时注意
npm install react-native-vector-icons --save
或者
yarn add react-native-vector-icons
注意:目前npm5存在安装新库时会删除其他库的问题,可能后面会修复导致项目无法正常运行。请尽量使用yarn代替npm操作。
执行以下命令链接原生库
react-native link react-native-vector-iconsios配置(ios需要单独导入字体文件,安卓link完就可以用了)
ios必须要配置 如果不配置会报错Unrecognized font family ‘Ionicons’如果还是报错
我的解决方法
在node_modules目录找到react-native-vector-icons目录,删除掉,使用yarn命令重新下载,link命令,ios配置,关闭所有服务,使用xcode安装。问题解决。
DrawerNavigator
代码
'use strict';
import React,{Component} from 'react';
352152
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
PixelRatio,
} from 'react-native';
import { DrawerNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
const HomeScreen=({navigation})=>(
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>HomeScreen</Text>
<Button
onPress={()=>(navigation.toggleDrawer())}
title="Open Drawer"
></Button>
</View>
);
const ProfileScreen=()=>(
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}><Text>ProfileScreen</Text></View>
);
const RootDrawer =DrawerNavigator({
Home:{
screen:HomeScreen,
navigationOptions:{
drawerLabel:'MyHome',
drawerIcon:({tintColor, focused })=>(
<Ionicons
name={'ios-home'}
size={20}
style={{ color: tintColor }}
></Ionicons>
),
},
},
Profile:{
screen:ProfileScreen,
navigationOptions:{
drawerLabel:'MyProfile',
drawerIcon:({tintColor})=>(
<Ionicons
name={'ios-person'}
size={20}
style={{color:tintColor}}
></Ionicons>
),
},
}
});
export default RootDrawer;
效果图
点击Button会打开侧拉菜单


嵌套导航
标题仅适用于StackNavigator。 本来想切换tab页面,标题也跟着切换,折腾了半天也没做出来。官方文档说的意思是标题仅适用于StackNavigator
这个例子意思是:StackNavigator导航里面嵌套TabNavigator导航。
把StackNavigator的主页面替换成了TabNavigator两个tab页面,在tab页面点击按钮跳转到StackNavigator导航页面并携带数据。
'use strict';
import React,{Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
PixelRatio,
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import { createBottomTabNavigator } from "react-navigation";
/**
* Home页面
*/
class HomeScreen extends Component{
static navigationOptions={
title:'Welcome',
};
render(){
const { navigate } = this.props.navigation;
return(
<View>
<Text>Hello, Navigation!</Text>
<Button
onPress={ ()=>{navigate('Chat',{user:'Lucy'})}}
title='Chat with Lucy'
></Button>
</View>
);
}
}
/**
* 聊天界面
*/
class ChatScreen extends Component{
static navigationOptions=({navigation})=>({
title:navigation.state.params.user,
});
render(){
const userTitle=this.props.navigation.state.params.user;
const {params} = this.props.navigation.state;
return(
<Text>{params.user}</Text>
);
}
}
class RecentChatsScreen extends Component{
render(){
return(
<View>
<Text>List of recent chats</Text>
<Button
onPress={ () => {this.props.navigation.navigate('Chat',{user:'RecentChatsScreen'})}}
title='Chat with Lucy'
></Button>
</View>
);
}
}
class AllContactsScreen extends Component{
render(){
return(
<View>
<Text>List of all contacts</Text>
<Button
onPress={ () => {this.props.navigation.navigate('Chat',{user:'AllContactsScreen'})}}
title='Chat with Lucy'
></Button>
</View>
);
}
}
/**
* 页面嵌套
*/
export const MainScreenNavigator=createBottomTabNavigator({
Recent:{
screen:RecentChatsScreen,
navigationOptions:{
headerTitle:'My Chat',
}
},
All:{
screen:AllContactsScreen,
navigationOptions:{
headerTitle:'My All',
}
},
});
export const SimpleApp=StackNavigator({
HomeScreen:{
screen:MainScreenNavigator,
navigationOptions:{
title:'My Chats',
}
},
Chat:{
screen:ChatScreen,
Navigation:{
}
}
});
AppRegistry.registerComponent('MyApp', () => SimpleApp);
需要注意一点
点击按钮打开侧拉侧单下面这种做法是错误的。因为过时了。
<Button
onPress={() => navigation.navigate('DrawerToggle')}
title="Open Drawer"
/>
解决办法: 使用最新的API
onPress={()=>(navigation.toggleDrawer())}
标题仅适用于StackNavigator。
添加右侧的按钮
'use strict';
import React,{Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
PixelRatio,
TextInput,
//屏幕组件与标题的交互 记得导入
ActivityIndicator,
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import { createBottomTabNavigator } from "react-navigation";
/**
* Home页面
*/
class HomeScreen extends Component{
static navigationOptions={
title:'Welcome',
};
render(){
const { navigate } = this.props.navigation;
return(
<View>
<Text>Hello, Navigation!</Text>
<Button
onPress={ ()=>{navigate('Chat',{user:'Lucy'})}}
title='Chat with Lucy'
></Button>
</View>
);
}
}
/**
* 聊天界面
*/
class ChatScreen extends Component{
static navigationOptions=({navigation})=>{
console.log(navigation);
const {state,setParams} = navigation;
const isInfo = state.params.mode === 'info';
const {user} = state.params;
//添加右侧的按钮
//动态修改标题 和 button的title
return{
title: isInfo ? `${user}'s Contact Info` : `Chat with ${state.params.user}`,
headerRight:(
<Button
title={isInfo ? 'Done' : `${user}'s info`}
onPress={()=>{setParams({mode:isInfo?'none' : 'info'})}}
></Button>
),
};
};
render(){
console.log(this);
const userTitle=this.props.navigation.state.params.user;
const {params} = this.props.navigation.state;
return(
<Text>{params.user}</Text>
);
}
}
class RecentChatsScreen extends Component{
render(){
return(
<View>
<Text>List of recent chats</Text>
<Button
onPress={ () => {this.props.navigation.navigate('Chat',{user:'RecentChatsScreen'})}}
title='Chat with Lucy'
></Button>
</View>
);
}
}
class AllContactsScreen extends Component{
render(){
return(
<View>
<Text>List of all contacts</Text>
<Button
onPress={ () => {this.props.navigation.navigate('Chat',{user:'AllContactsScreen'})}}
title='Chat with Lucy'
></Button>
</View>
);
}
}
/**
* 页面嵌套
*/
export const MainScreenNavigator=createBottomTabNavigator({
Recent:{
screen:RecentChatsScreen,
navigationOptions:{
headerTitle:'My Chat',
}
},
All:{
screen:AllContactsScreen,
navigationOptions:{
headerTitle:'My All',
}
},
});
/**
* 屏幕组件与标题的交互
*/
class EditInfoScreen extends Component{
static navigationOptions= ({navigation}) =>{
// 3 获取navigation state 中 params 属性 使用解构赋值 并设置默认值
const {params={}} = navigation.state;
console.log(params);
console.log(params.handleSave);
//设置标题右侧按钮
let headerRight=(
<Button
title='Save'
// handleSave 是函数_handlerSave params.handleSave才会调用函数
onPress={params.handleSave? params.handleSave : ()=>null}
></Button>
);
console.log(params.isSaveing);
if(params.isSaveing){
headerRight = <ActivityIndicator/>;
}
return {headerRight};
}
//2. 编写state属性 存放数据
state={
nickName:'fengxing',
}
componentDidMount(){
this.props.navigation.setParams({handleSave:this._handlerSave});
console.log(this._handlerSave);
}
_handlerSave= ()=>{
console.log('_handlerSave');
this.props.navigation.setParams({isSaveing:true});
//saveInfo().then(()=>{
// this.props.navigation.setParams({isSaveing:false});
//});
}
render(){
return(
//1. 编写组件基本内容
<View>
<TextInput
style={{height: 400, borderColor: 'gray', borderWidth: 1,marginTop:30}}
placeholder={'Nickname'}
onChangeText={ (nickName) => this.setState({nickName}) }
multiline={true}
value={this.state.nickName}
>
</TextInput>
<Button
title='点击'
onPress = { ()=> this.props.navigation.setParams({isSaveing:false}) }
>
</Button>
</View>
);
}
}
/**
* 输出的视图
*/
export const SimpleApp=StackNavigator({
HomeScreen:{
screen:MainScreenNavigator,
navigationOptions:{
title:'My Chats',
}
},
Chat:{
screen:EditInfoScreen,
Navigation:{
}
}
});
AppRegistry.registerComponent('MyApp', () => SimpleApp);
内置导航器
react-navigation包含以下功能来帮助你创建导航器:
- StackNavigator - 一次只渲染一个页面,并提供页面之间跳转的方法。 当打开一个新的页面时,它被放置在堆栈的顶部
- TabNavigator - 渲染一个选项卡,让用户可以在几个页面之间切换
- DrawerNavigator - 提供一个从屏幕左侧滑入的抽屉
StackNavigator
API 定义
StackNavigator(RouteConfigs, StackNavigatorConfig)
RouteConfigs
路由配置对象是从路由名称到路由配置的映射,告诉导航器该路由应该呈现什么。
StackNavigator({
// For each screen that you can navigate to, create a new entry like this:
Profile: {
// `ProfileScreen` is a React component that will be the main content of the screen.
screen: ProfileScreen,
// When `ProfileScreen` is loaded by the StackNavigator, it will be given a `navigation` prop.
// Optional: When deep linking or using react-navigation in a web app, this path is used:
path: 'people/:name',
// The action and route params are extracted from the path.
// Optional: Override the `navigationOptions` for the screen
navigationOptions: ({navigation}) => ({
title: `${navigation.state.params.name}'s Profile'`,
}),
},
...MyOtherRoutes,
});
StackNavigatorConfig
router的选项:
-
initialRouteName- 设置堆栈的默认页面。 必须匹配RouteConfigs中的一个key。 -
initialRouteParams- 初始化路由的参数 -
navigationOptions- 用于页面的默认导航选项 -
paths- 用于覆盖RouteConfigs中设置的path的一个映射
视觉选项:
-
mode- 定义页面渲染和转换的风格:-
card- 使用标准的iOS和Android页面转换风格,此项为缺省。 -
modal- 使页面从屏幕底部滑入,这是一种常见的iOS模式。 只适用于iOS,在Android上不起作用。
-
-
headerMode- 定义标题该如何渲染:-
float- 渲染一个放在顶部的标题栏,并在页面改变时显示动画。 这是iOS上的常见模式。 -
screen- 每个页面上都有一个标题栏,标题栏与页面一起淡入淡出。 这是Android上的常见模式。 -
none- 没有标题栏
-
-
cardStyle- 使用这个属性覆盖或者扩展堆栈中单个Card的默认样式。 -
transitionConfig- 返回一个与默认页面的transitionConfig(参见类型定义)合并的对象的函数。 提供的函数将传递以下参数:-
transitionProps- 新页面跳转的属性。 -
prevTransitionProps- 上一个页面跳转的属性 -
isModal- 指定页面是否为modal。
-
-
onTransitionStart-card跳转动画开始时要调用的函数。 -
onTransitionEnd-card跳转动画结束时要调用的函数。
Screen Navigation Options
title
可当作headerTitle的备用的字符串。 此外,将用作tabBarLabel(如果嵌套在TabNavigator中)或drawerLabel(如果嵌套在DrawerNavigator中)的后备。
header
可以是React元素或给定了HeaderProps然后返回一个React元素的函数,显示为标题。 设置为null隐藏标题。
headerTitle
字符串、React元素或被当作标题的React组件。默认显示title属性的值。当使用一个组件时,它会收到allowFontScaling,style和children属性。 标题字符串在children中进行传递。
headerTitleAllowFontScaling
标题栏中标题字体是否应该缩放取决于文本大小是否可以设置。 默认为true。
headerBackTitle
iOS上的返回按钮的文字使用的字符串,或者使用null来禁用。 默认为上一个页面的headerTitle。
headerTruncatedBackTitle
当headerBackTitle不适合在屏幕显示时(一般是因为文字太多),返回按钮使用的标题字符串。 默认是Back。
headerRight
显示在标题栏右侧的React元素。
headerLeft
用于在标题栏左侧展示的React元素或组件。当一个组件被渲染时,它会接收到很多的属性(onPress, title, titleStyle 等等, - 请检查 Header.js 的完整列表)
headerStyle
标题栏的样式
headerTitleStyle
标题栏中标题的样式
headerBackTitleStyle
标题栏中返回按钮标题的样式
headerTintColor
标题栏的色调
headerPressColorAndroid
material design中的波纹颜色 (仅支持Android >= 5.0)
gesturesEnabled
是否可以使用手势来关闭此页面。 在iOS上默认为true,在Android上默认为false。
gestureResponseDistance
一个对象,用以覆盖从屏幕边缘开始触摸到手势被识别的距离。 它具有以下属性:
-
horizontal- 数值型 - 水平方向的距离,默认值25 -
vertical- 数值型 - 垂直方向的距离,默认值135.
字符串,用来设置关闭页面的手势方向,默认(default)是从做往右,inverted是从右往左
/**
* 输出的视图
*/
export const SimpleApp=StackNavigator({
HomeScreen:{
screen:MainScreenNavigator,
navigationOptions:{
title:'My Chats',
}
},
Chat:{
screen:EditInfoScreen,
Navigation:{
}
}
},{
//定义标题该如何渲染 none 没有标题 float 淡入淡出 screen
headerMode: 'screen',
//弹出方式
mode:'modal',
navigationOptions: {
//是否可以使用手势来关闭此页面。 在iOS上默认为true,在Android上默认为false。
gesturesEnabled: false,
},
//
transitionConfig:() => ({
transitionSpec:{
duration:300,
easing:Easing.out(Easing.poly(4)),
timing: Animated.timing,
}
})
});
TabNavigator
API 定义
TabNavigator(RouteConfigs, TabNavigatorConfig)
TabNavigatorConfig
-
tabBarComponent- 用作渲染tab bar的组件,例如TabBarBottom(这是iOS上的默认设置),TabBarTop(这是Android上的默认设置)。 -
tabBarPosition-tab bar的位置, 可选值:'top'or'bottom' -
swipeEnabled- 是否允许滑动切换tab页 -
animationEnabled- 是否在切换tab页时使用动画 -
configureTransition- 给定currentTransitionProps和nextTransitionProps的函数,其返回一个配置对象,该对象用于描述tab页之间的动画 -
initialLayout- 可以传递包含初始height和width的可选对象,用以防止react-native-tab-view渲染中一个帧的延迟 -
tabBarOptions- 配置tab bar,详情见下文
传递到底层路由,用于修改导航逻辑的几个选项:
-
initialRouteName- 第一次加载tab bar时路由的routeName -
order- 定义了tab bar顺序的一个routeNames数组 -
paths- 提供routeName到path config的映射,它覆盖了routeConfigs中设置的path。 -
backBehavior- 返回按钮是否会导致tab切换到初始tab页? 如果是,则设置为initialRoute,否则为none。 缺省为initialRoute。
TabBarBottom的tabBarOptions (TabBarBottom为iOS的默认tab bar)
-
activeTintColor- 当前选中的tab bar的文本颜色和图标颜色 -
activeBackgroundColor- 当前选中的tab bar的背景色 -
inactiveTintColor- 当前未选中的tab bar的文本颜色和图标颜色 -
inactiveBackgroundColor- 当前未选中的tab bar的背景色 -
showLabel- 是否显示tab bar的文本,默认是true -
style-tab bar的样式 -
labelStyle-tab bar的文本样式 -
tabStyle-tab页的样式 -
allowFontScaling- 文本字体大小是否可以缩放取决于该设置,默认为true。
tabBarOptions: {
activeTintColor: '#e91e63',
labelStyle: {
fontSize: 12,
},
style: {
backgroundColor: 'blue',
},
}
TabBarTop的tabBarOptions (TabBarTop为Android的默认tab bar)
-
activeTintColor- 当前选中的tab bar的文本颜色和图标颜色 -
inactiveTintColor- 当前未选中的tab bar的文本颜色和图标颜色 -
showIcon- 是否显示tab bar的图标,默认是false -
showLabel- 是否显示tab bar的文本,默认是true -
upperCaseLabel- 是否将文本转换为大小,默认是true -
pressColor- material design中的波纹颜色(仅支持Android >= 5.0) -
pressOpacity- 按下tab bar时的不透明度(仅支持iOS和Android < 5.0). -
scrollEnabled- 是否允许滑动切换 -
tabStyle- tab页的样式 -
indicatorStyle- tab 页指示符的样式 (tab页下面的一条线). -
labelStyle-tab bar的文本样式 -
iconStyle-tab bar的图标样式 -
style-tab bar的样式 -
allowFontScaling- 文本字体大小是否可以缩放取决于该设置,默认为true。
栗子:
tabBarOptions: {
labelStyle: {
fontSize: 12,
},
tabStyle: {
width: 100,
},
style: {
backgroundColor: 'blue',
},
}
Screen Navigation Options
title
可以用作headerTitle 和 tabBarLabel后备的通用标题。(headerTitle 和 tabBarLabel未设置时,就会使用title的值替代)
tabBarVisible
tab bar是否可见,缺省是true
swipeEnabled
是否允许tab页之间滑动切换,如果未设置,则使用TabNavigatorConfig的swipeEnabled选项
tabBarIcon
用于在tab bar中展示的React元素或一个传入{ focused: boolean, tintColor: string }返回React.Node的函数
tabBarLabel
用于在tab bar中展示的一个字符串或者一个传入{ focused: boolean, tintColor: string }返回React.Node的函数,如果未定义,则使用页面的title属性。如果像隐藏文本,请参阅上一小节中讲到的tabBarOptions.showLabel
tabBarOnPress
tab被点击时的回调函数;参数是一个对象,包含一下属性:
-
previousScene: { route, index }:正在离开的页面 -
scene: { route, index }被点击的页面 -
jumpToIndex执行跳转操作必须的参
DrawerNavigator
使用...navigate('DrawerOpen')和...navigate('DrawerClose')打开和关闭抽屉
this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer