在上一节Navigation组件,我们使用系统提供的导航组件做了一个跳转的例子,不过其实战能力不强,这里推荐一个超牛逼的第三方库:react-navigation。在讲React-navigation之前,我们先看一下常用的导航组件。
导航控件
常见的导航主要分为三种:
1.StackNavigator :类似于普通的Navigator,屏幕上方导航栏
2.TabNavigator:obvIoUsly,相当于iOS里面的TabBarController,屏幕下方标签栏
3.DrawerNavigator:抽屉效果,左侧滑出这种效果。
Navigation 使用
在你使用navigation的每一个界面navigation都提供相关的属性和响应方法,常见的有:
navigate定义跳转到另一个页面
调用此方法去链接你的其他界面,主要有以下参数:
·routeName- 目标路由名称,将在你的app router中注册
·params-将参数合并到目标router中
·action-(高级)sub-action ,如果该界面是一个navigator的话,将运行这个sub-action
例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
class HomeScreen extends React.Component {
render() {
const {navigate} = this.props.navigation;
return (
<View>
<Text>This is the home screen of the app</Text>
<Button
onPress={() => navigate(
'Profile',{name:
'Brent'})}
title=
"点击我跳转"
/>
</View>
)
}
}
state当前路由状态
每个界面通过this.props.navigation.state去访问它的router,state其中包括了:
·routeName - router配置的名称
·key-用来区分router的唯一标示
·params-可选的一些string参数
setParams-更改router中的参数
该方法允许界面更改router中的参数,可以用来动态的更改header的内容
goBack-返回,pop回上一级
dispatch -使用dispatch可以向任何navigation传递一些其他的action,主要支持的action有
Navigate使用
例如:
1
2
3
4
5
6
7
8
9
10
import { NavigationActions }
from 'react-navigation'
const navigationAction = NavigationActions.navigate({
routeName:
params: {},
action: NavigationActions.navigate({ routeName:
'SubProfileRoute'})
})
this.props.navigation.dispatch(navigationAction)
Reset
Reset方法会擦除掉所有的导航状态,并且使用新的结果替代。
1
2
3
4
5
6
7
8
9
import { NavigationActions }
const resetAction = NavigationActions.reset({
index:
0,actions: [
NavigationActions.navigate({ routeName:
'Profile'})
]
})
this.props.navigation.dispatch(resetAction)
SetParams
为指定的router更新参数,该参数必须是已经存在于router的param中。
1
2
3
4
5
6
7
8
import { NavigationActions }
const setParamsAction = NavigationActions.setParams({
// these are the new params that will be merged into the existing route params
key:
'screen-123',})
this.props.navigation.dispatch(setParamsAction)
StackNavigator使用
StackNavigator使用比较简单,看一个常见的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
MyHomeScreen Component {
static navigationOptions = {
title:
'Home',0);
Box-sizing: border-
Box;">//设置navigator的title
}
render() {
return (
<Button
onPress={() => this.props.navigation.navigate(
'Lucy'})}
title=
"Go to Lucy's profile"
/>
);
}
}
const ModalStack = StackNavigator({
Home: {
screen: MyHomeScreen,},Profile: {
path:
'people/:name',screen: MyProfileScreen,});
StackNavigatorConfig
option for the route(路由选项):
·initialRouteName -为stack设置默认的界面,必须和route configs里面的一个key匹配。
·initialRouteParams - 初始路由的参数。
·navigationOptions- 屏幕导航的默认选项。
·paths-route config里面路径设置的映射。
Visual Option(视觉选项):
·mode- 定义渲染(rendering)和转换(transitions)的模式,两种选项:
1) card-使用标准的ios和Android的界面切换,这是默认的。
2)modal- 仅在iOS端有用,即模态出该视图。
·headerMode- 指定header应该如何被渲染,选项:
1)float- 共用一个header 意思就是有title文字渐变效果。
2)screen- 各用各的header 意思就是没有title文字渐变效果。
3)none- 没有header。
·cardStyle- 使用该属性继承或者重载一个在stack中的card的样式。
·onTransitionStart- 一个函数,在换场动画开始的时候被激活。
·onTransitionEnd- 一个函数,在换场动画结束的时候被激活。
Navigation Options
你还可以定义一个静态的navigationOptions在你的组件之上。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
lass ProfileScreen extends React.Component {
//设置navigation选项
static navigationOptions = {
//标题
title:
({ state }) => `
${state.params.name}'s Profile!`,
//头部定义了一个右按钮,来改变edit的状态 ing或者完成
header:
({ state,setParams }) => ({
// Render a button
on the right side
of the header
// When pressed switches the screen to edit mode.
right: (
<Button
title={state.params.editing ?
'Done' :
'Edit'}
onPress={
() => setParams({
editing: state.params.editing ?
false :
true})}
/>
),}),};
...
常用的配置中,主要有以下参数需要注意:
1)visible - bool值,header是否可见。
2)title-标题 String或者是一个react节点
3)backTitle-返回按钮在iOS平台上,默认是title的值
4)right- react 节点显示在header右边,例如右按钮
5)left- react 节点显示在header左边,例如左按钮
6)style-header的style
7)titleStyle- header的title的style (^__^) 嘻嘻……
8)tintColor- header的前景色
·cardStack- 配置card stack
react-navigation
说完常见的导航器,我们在看看本文的重点:react-navigation的使用。
首先看一下效果:
1,在项目目录下,安装React-navigation库
1
-- navigation
2,使用StactkNavigator来管理堆栈。暂且命名为HomeScreen.js。默认入口页面代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
import React from
'react';
import {
AppRegistry,Text,} from
'react-native';
import { StackNavigator } from
'react-navigation';
static navigationOptions = {
title: 'Welcome',0); Box-sizing: border-Box;">//标题
};
render() {
return <Text>Hello,Navigation!</Text>;
}
}
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },});
AppRegistry.registerComponent(
'SimpleApp',() => SimpleApp);
运行效果:
3,添加一个新的页面
1
2
3
4
5
6
7
8
9
10
11
12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
ChatScreen 'Chat with Lucy',};
render() {
return (
<View>
<Text>Chat with Lucy</Text>
</View>
);
}
}
4,在HomeScreen中添加一个button组件,使用routeName Chat关联到ChatScreen。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello,Chat App!</Text>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
这段代码主要是给Button绑定onPress事件。这时候,我们使用的两个跳转的页面需要在StackNavigator进行注册:
1
2
3
4
//新添加的页面
});
所以完整的代码是:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
Component {
static navigationOptions = {
title: //设置标题内容
};
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello,Navigation!</Text>
<Button
onPress={() => navigate('Chat',{user:'Lucy'})}
title="Chat with Lucy"/>
</View>
);
}
}
const SimpleApp = StackNavigator({
Home: {screen: HomeScreen},Chat:{screen:ChatScreen},});
参数传递
在页面的跳转过程中,往往会伴随着参数的传递。
navigation参数传递
1,在第一个页面定义参数,将参数传值给需要传值的页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
constructor(props) ;
}
...
if(navigator)
})
}
2,如果需要监听页面的state状态
1
onChangeText={(text) => this.setState({user: text})}
3,另一个页面接受参数
1
2
3
4
5
6
7
8
componentDidMount() {
//这里获取从FirstPageComponent传递过来的参数: id
this.setState({
user:this.props.user,pwd:this.pwd
})
}
4,去的传过来的值:
1
value={this.state.user }
react-navigation参数传递
对于 react-navigation参数的传递,使用上比较简单,只需要在navigate中加一个json格式的对象即可,如:
1
navigate('Lucy' })
然后在接受的页面:
static
navigationOptions = {
title: ({ state }) => `Chat with ${state.params.user}`,};
render() {
const { params } = this.props.navigation.state;
return (
<View>
<Text>Chat with {params.user}</Text>
</View>
);
}
}
所以,你就可以看到如下的效果:
TabNavigator
TabNavigator类似于底部导航效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
const Tabs = TabNavigator({
Home: {
screen: Home,navigationOptions: {
tabBar: {
label: '首页',icon: ({tintColor}) => (<Image source={require('./app/images/home.png')} style={[{tintColor: tintColor},styles.icon]}/>),}
},Bill: {
screen: Bill,navigationOptions: {
tabBar: {
label: '账单',0); Box-sizing: border-Box;">'./app/images/bill.png')} style={[{tintColor: tintColor},Me: {
screen: Me,0);
Box-sizing: border-
Box;">'我',0);
Box-sizing: border-
Box;">'./app/images/me.png')} style={[{tintColor: tintColor},}
}
},{
animationEnabled:
false,0);
Box-sizing: border-
Box;">// 切换
页面时是否有动画
效果
tabBarPosition:
'bottom',0);
Box-sizing: border-
Box;">//
显示在底端,android 默认是
显示在
页面顶端的
swipeEnabled:
// 是否可以左右滑动切换tab
backBehavior:
'none',0);
Box-sizing: border-
Box;">// 按 back 键是否
跳转到第一个Tab(
首页), none 为不
跳转
tabBarOptions: {
activeTintColor:
'#ff8500',0);
Box-sizing: border-
Box;">//
文字和
图片选中颜色
inactiveTintColor:
'#999',0);
Box-sizing: border-
Box;">//
文字和
图片未选中颜色
showIcon:
true,0);
Box-sizing: border-
Box;">// android 默认
不显示 icon,需要设置为 true 才会
显示
indicatorStyle: {
height:
0
},style: {
backgroundColor:
'#fff',0);
Box-sizing: border-
Box;">// TabBar 背景色
},labelStyle: {
fontSize:
10,0);
Box-sizing: border-
Box;">//
文字大小
},});
DrawerNavigator
DrawerNavigator类似于抽屉侧滑效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
const DrawerNav = DrawerNavigator({
Home: { screen: Home },Bill: { screen: Bill },Me: { screen: Me },HomeTwo: { screen: HomeTwo },HomeThree: { screen: HomeThree },HomeFour: { screen: HomeFour },BillTwo: { screen: BillTwo },BillThree: { screen: BillThree }
},{
drawerWidth:
200,0);
Box-sizing: border-
Box;">// 抽屉宽
drawerPosition:
'left',0);
Box-sizing: border-
Box;">// 抽屉在左边还是右边
contentOptions: {
initialRouteName: Home,0);
Box-sizing: border-
Box;">// 默认
页面组件
activeTintColor:
'white',0);
Box-sizing: border-
Box;">// 选
中文字颜色
activeBackgroundColor:
// 选中背景颜色
inactiveTintColor:
'#666',0);
Box-sizing: border-
Box;">// 未选
中文字颜色
inactiveBackgroundColor:
// 未选中背景颜色
style: {
}
}
});
iOS版设置
在iOS中使用react-navigation需要注意以下几点:
使用Xcode设置Schemes;
在AppDelegate添加一下代码:
1
2
3
4
5
- (
BOOL)application:(
UIApplication *)application openURL:(
NSURL *)url
sourceApplication:(
NSString *)sourceApplication annotation:(
id)annotation {
return [RCTLinkingManager application:application openURL:url
sourceApplication:sourceApplication annotation:annotation];
}
js组件在注册路由时设置唯一的路径path,例如Home2: { screen: Home2,path:’app/Home2’ };
在手机浏览器访问demo4://app/Home2,弹窗选择打开,就可以打开demo4 app并进到Home2页面。
react-native-tab-navigator
直接上代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
/**
* Sample React Native App
*
https:
//github.com/facebook/react-
native
*
@flow
*/
import React,{ Component } from
'react';
import TabNavigator from
'react-native-tab-navigator';
import {
AppRegistry,StyleSheet,Image,View
} from
'react-native';
const TabNavigatorItem =TabNavigator.Item;
//默认选项
const TAB_HOME_NORMAL=
require(
'./image/tabbar_homepage.png');
const TAB_MINE_NORMAL=
'./image/tabbar_mine.png');
//选中
const TAB_HOME_PRESS=
'./image/tabbar_homepage_selected.png');
const TAB_MINE_PRESS=
'./image/tabbar_mine_selected.png');
export default HelloWord Component {
//默认选中
constructor(){
super();
this.state={
selectedTab:
//点击
方法
onPress(tabName){
if(tabName){
this.setState({
selectedTab:tabName,}
);
}
}
//渲染选项
renderTabView(title,tabName,tabContent,isBadge){
var tabNomal;
var tabPress;
switch (tabName) {
case 'Home':
tabNomal=TAB_HOME_NORMAL;
tabPress=TAB_HOME_PRESS;
break;
case 'Mine':
tabNomal=TAB_MINE_NORMAL;
tabPress=TAB_MINE_PRESS;
break;
default:
}
return(
<TabNavigatorItem
selected={
this.state.selectedTab===tabName}
title={title}
titleStyle={styles.tabText}
selectedTitleStyle={styles.selectedTabText}
renderIcon={
()=><Image style={styles.icon} source={tabNomal}/>}
renderSelectedIcon={
()=><Image style={styles.icon} source={tabPress}/>}
onPress={
()=>this.onPress(tabName)}
renderBadge={
()=>isBadge?<View style={styles.badgeView}><Text style={styles.badgeText}>
15</Text></View>:
null}
>
<View style={styles.page}><Text>{tabContent}</Text></View>
</TabNavigatorItem>
);
}
//自定义TabView
tabBarView(){
return (
<TabNavigator
tabBarStyle={styles.tab}
>
{
this.renderTabView(
'首页模块',
true)}
{
'我的',0);
Box-sizing: border-
Box;">'Mine',0);
Box-sizing: border-
Box;">'我的模块',102);
Box-sizing: border-
Box;">false)}
</TabNavigator>
);
}
//渲染界面
render() {
var tabView=
this.tabBarView();
return (
<View style={styles.container}>
{tabView}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex:
1
},
tabText: {
fontSize:
color:
'black'
},0);">selectedTabText: {
'green'
},0);">tab:{
height:
52,0);">alignItems:
'center',0);">backgroundColor:
'#f4f5f6',0);">tabIcon:{
width:
25,0);">height:
badgeView:{
22,102);
Box-sizing: border-
Box;">14,0);
Box-sizing: border-
Box;">'#f85959',0);">borderWidth:
1,0);">marginLeft:
marginTop:
3,0);">borderColor:
'#FFF',0);">justifyContent:
borderRadius:
8,0);">badgeText:{
color:
fontSize:
icon: {
width:
22
},0);">page: {
justifyContent:
alignItems:
backgroundColor:
'#FFFFFF'
},});
AppRegistry.registerComponent
('HelloWord',() => HelloWord);
参考:React Native页面参数传递
https://reactnavigation.org/docs/intro/
react-native-tab-navigator封装