ReactNative开发——Navigation的使用
React Native 0.43之前 ‘react-native’包里面,但0.43之后了’rea移除了rect-native’。网上的大部分资料,也是ReactNative 0.43之前的 Navigator的用法,然而我用的0.44版本在开发,这就….
参考: http://facebook.github.io/react-native/docs/navigation.html
安装 ‘react-navigator’依赖
于是我按着文档 https://reactnavigation.org/docs/intro/ 来安装:
在项目目录下执行命令安装:
npm install --save react-navigator
结果呵呵哒:
E:\hybrid\react_native_pro\Project02>npm install
npm WARN peerDependencies The peer dependency react@* included from react-navigation will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
npm WARN peerDependencies The peer dependency react@* included from react-native-drawer-layout-polyfill will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
npm WARN peerDependencies The peer dependency react@* included from react-native-tab-view will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.
npm ERR! install trying to install 15.5.4 to E:\hybrid\react_native_pro\Project02\node_modules\react-navigation\node_modules\react
npm ERR! install but already installed versions [ '15.5.4' ]
npm ERR! Windows_NT 10.0.14393
npm ERR! argv "D:\\Program Files\\nodejs\\node.exe" "C:\\Users\\Administrator\\AppData\\Roaming\\npm\\node_modules\\npm\\bin\\npm-cli.js" "install"
npm ERR! node v4.4.7
npm ERR! npm v2.15.12
npm ERR! code EPEERINVALID
npm ERR! peerinvalid The package react@16.0.0-alpha.6 does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer react-native@0.44.0 wants react@16.0.0-alpha.6
npm ERR! peerinvalid Peer react-navigation@1.0.0-beta.11 wants react@*
npm ERR! peerinvalid Peer react-test-renderer@16.0.0-alpha.6 wants react@^16.0.0-alpha.6
npm ERR! Please include the following file with any support request:
npm ERR! E:\hybrid\react_native_pro\Project02\npm-debug.log```
最后我的解决办法是 安装npm3:
npm install -g npm@3
然后重新执行上面的命令安装。
开始学习
HelloWorld
首先根据官方文档的实例代码编写出来看看效果:
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
'user react'
import React, {Component} from 'react';
import {AppRegistry, View, Button, Text} from 'react-native';
import {StackNavigator} from 'react-navigation'
/**
* 主页面
*/
class HomeScreen extends Component {
static navigationOptions = {
/*设置标题*/
title: 'Welcome'
}
render() {
const {navigate} = this.props.navigation;
return (
<View>
<Text> Hello,Navigator</Text>
<Button
title="Chat With Lucy"
//跳转第二个页面,第二个参数,向第二个页面传入参数{user:'Lucy'}
onPress={() => navigate('Chat', {user: 'Lucy'})}
>
</Button>
</View>
);
}
}
/**
* 第二个页面
*/
class ChatScreen extends Component {
/*可以定义一个函数来读取上个页面传过来的参数*/
static navigationOptions = (({navigation}) => ({
title: `Chat with ${navigation.state.params.user}`
}))
render() {
const { params } = this.props.navigation.state;
return (
<View>
<Text> Hello , {params.user}</Text>
</View>
);
}
}
const Project02 = StackNavigator({
Home: {screen: HomeScreen},
Chat: {screen: ChatScreen},
});
AppRegistry.registerComponent('Project02', () => Project02);
该代码实现了:
1.定义了2个页面 HomeScreen和ChartScreen。在HomeScreen中有个按钮,点击跳转到到第二个页面并传参。
Navigators
介绍
Navigators是用来定义为你应用顶用导航架构用的,你也可以通过配置让它为您渲染公共的元素,比如头部或者TabBar。
用来构建Navigator的函数
- StackNavigator —— 用来提供类似“栈”的那张导航,比如启动一个页面,这个新的页面覆盖在旧的页面上,继续按返回键这个新的页面将“弹出”又出现旧的页面。
- TabNavigator —— 提供一个TabBar让用户在几个页面之前切换,这种类似:以Android为例,效果等于TabLayout+ViewPager+Fragment那种。
- DrawerNavigator ——提供一个抽屉,左滑出现。
使用Navigators
使用Navigators我们主要学习2个属性,下文Screen指的是我们的页面组件(即上文,HelloWorld中的HomeScreen,和ChildScreen等)
* Screen navigation prop ,我们可以使用它来调用导航操作,比如启动另一个页面。
* Screen navigationOptions, 我们可以用来定义navigator的显示属性,比如(title,tab label等)
在顶层组件使用导航
上面一个条目,我们讲到用 screen 的 navigation prop可以进行导航操作,但如果我们要在外部操作导航怎么办呢?
我们可以这样:声明一个Navigators的引用,我们可以使用这个引用进行操作,例如:
const AppNavigator = StackNavigator(SomeAppRouteConfigs);
class App extends React.Component {
someEvent() {
// call navigate for AppNavigator here:
this.navigator && this.navigator.dispatch({ type: 'Navigate', routeName, params });
}
render() {
return (
<AppNavigator ref={nav => { this.navigator = nav; }} />
);
}
}
注意,这种解决方案应该只用在最顶层的navigator。
Navigation 容器
当navigation prop没有设置的时候,这个Navigation会自动显示在顶层,她将是一个透明的容器。
当渲染navigaor的时候,这个navigation props 是可选的,如果不设置,它也会有一些默认的操作,比如可以处理URL,外部链接、android会返回键等。这是因为这些系统自带的navigator(StackNavigator、TabNavigator)他们内部使用了createNavigationContainer
方法,通常,这个方法被用来设置 navigator prop 去支持一些函数。
顶部Navigators接受以下属性:
onNavigationStateChange(prevState, newState, action)
这个用来获得Navigation的状态,它可以接收前一个状态,和最新的状态,以及操作
uriPrefix
用来设置url的前缀,表示那些url可以被我们的app处理。
下面,我贴一个例子,来演示以下 uriPrefix
和onNavigationStateChange(prevState, newState, action)
的用法
/**
* Created by Administrator on 5/27/2017.
*/
import React from 'react';
import {
AppRegistry,
Text,
View,
Button,
} from 'react-native';
import {TabNavigator, StackNavigator} from 'react-navigation';
class RecentChatsScreen extends React.Component {
render() {
return <Text>List of recent chats</Text>
}
}
class AllContactsScreen extends React.Component {
render() {
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => this.props.navigation.navigate('Chat', {user: 'Lucy'})}
title="Chat with Lucy"
/>
</View>
);
}
}
class ChatScreen extends React.Component {
static navigationOptions = ({navigation}) => {
const {state, setParams} = navigation;
const isInfo = state.params.mode === 'info';
const {user} = state.params;
return {
title: isInfo ? `${user}'s Contact Info` : `Chat with ${user}`,
headerRight: (<Button title={isInfo ? 'Done' : `${user}'s Info`}
onPress={() => setParams({mode: isInfo ? 'none' : 'info'})}
/>)
};
};
render() {
const {params} = this.props.navigation.state;
return (
<View>
<Text>Chat with {params.user}</Text>
</View>
);
}
}
const MainScreenNavigator = TabNavigator({
Recent: {
screen: RecentChatsScreen
},
All: {
screen: AllContactsScreen,
},
});
// MainScreenNavigator.navigationOptions = {title: "Main"};
const SimpleApp = StackNavigator({
// 使用 header:null 去掉StackNavigator的导航栏头部
Home: {screen: MainScreenNavigator, navigationOptions: ({navigation}) => ({header: null}),},
Chat: {
screen: ChatScreen,
//路径,user为可以接受的参数
path: 'chat1/:user',
}
})
const MainApp = () => <SimpleApp
//设置 URL's Schema,和 Host
uriPrefix={'chat://chat/'}
onNavigationStateChange={(preState, newState, action) => {
console.log('preState:' + JSON.stringify(preState)
+ ',newState:' + JSON.stringify(newState) + ',action:' + JSON.stringify(action));
}}/>
AppRegistry.registerComponent('Project05', () => MainApp);
上述代码设置了 uriPrefix
为 ‘chat://chat/,并设置了 ChatScreen中的 path为:
chat1/:user, 其中
:user`表示接受参数 user
那么我们可以使用外部的URL来启动这个页面,
我们以Android为例,还需要在AndroidMainifest.xml中的Activity添加一下Intent-Filter。
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"></category>
<data android:scheme="chat"
android:host="chat"></data>
</intent-filter>
安装成功之后,我们在命令行输入:adb shell am start -W -a android.intent.action.VIEW -d "chat://chat/chat1/blueberry"
就可跳转到ChatScreen那个页面了,并传入了参数为blueberry
。
相关的ios也可以用外部URL访问本应用的页面,可以参考:https://reactnavigation.org/docs/guides/linking
StackNavigator
StackNavigator用来解决屏幕跳转,用它的效果页面导航效果|类似于栈,新启动的页面覆盖在原先的页面上。
使用
/**
* Created by blueberry on 6/15/2017.
*/
import React, {Component} from 'react';
import {StyleSheet, View, Button, Text, AppRegistry} from 'react-native';
import {StackNavigator} from 'react-navigation';
class MainScreen extends Component {
static navigationOptions = {
title: 'Home',
}
render() {
return (
<View style={{justifyContent: 'center', alignItems: 'center'}}>
<Text>{this.props.navigation.state.params.content || ''}</Text>
<Button title="Go to Profile"
onPress={() => this.props.navigation.navigate('Profile', {
title: 'blueberryTitle',
content: 'blueberryContent'
})}/>
</View>
);
}
}
class Profile extends Component {
static navigationOptions = ({navigation}) => ( {
title: navigation.state.params.title,
})
render() {
return (
<View>
<Text>{this.props.navigation.state.params.content}</Text>
</View>
);
}
}
const App = StackNavigator(
/**
* 路由配置
*/
{
Home: {screen: MainScreen},
Profile: {screen: Profile, navigationOptions: {headerRight: null}},
},
/**
* StackNavigator配置,也可以省略。
*/
{
// 配置初始化路由名称
initialRouteName: 'Home',
// 配置初始化路由的参数
initialRouteParams: {content: '初始化传入的参数'},
// 配置默认的 navigationOptions
navigationOptions: {headerRight: <Text>右边Header</Text>},
// 转场动画开始的回到
onTransitionStart: () => {
console.log('start')
},
}
);
AppRegistry.registerComponent('Project05', () => App);
API 定义
StackNavigator(RouteConfigs, StackNavigatorConfig)
这个函数接受2个参数,RouteConfigs和StackNavigatorConfig,其中StatckNavigatorConfig
可以省略,如果省略,则默认选择RouteConfigs
中定义的第一个路由。
RoutConfigs
这个路由配置类,是一个Map结构,key是路由的明城,value 是路由的配置。
StackNavigator(
{ // 以下定义了一个路由,Profile为路由的名称,对应的值则是路由的配置
Profile: {
// `ProfileScreen` 是一个 React UI组件的定义,它就是这个路由的界面
screen: ProfileScreen,// 当 `ProfileScreen` 被StackNavigator加载之后,他将会有一个`navigation` 属性。
// 这个是一个可选项,如果想让这个界面可以被外部链接启动,可以设置这个,:name是用来传入参数的,这个上文讲过。
path: 'people/:name',
// 设置这个可以覆盖我们在React Component中设置的navigationOptions属性
navigationOptions: ({navigation}) => ({
title: `${navigation.state.params.name}'s Profile'`,
}),
},
...MyOtherRoutes,
});
StackNavigatorConfig
属性 | 作用 |
---|---|
initialRouteName | 设置初始化路由名称 |
initialRouteParams | 设置初始化路由的参数 |
navigationOptions | 设置默认的 navigationOptions (这个参数下文将要介绍) |
paths | map结构,覆盖在路由配置中的path |
mode | 定义渲染的和跳转动画的风格,可以设置为card,modal。默认为card。modal可以使界面跳转的而动画是从底部逐渐显示到整个屏幕,这个只对ios有效,因为android,默认转场动画就是从底部逐渐显示到真个屏幕 |
headerMode | 指定如何渲染头部,可以设置为float,screen,none。如果设置为none,则不会有头部;如果设置为float, 页面跳转时,header是一直在顶部,而且如果header变化了的话,会有动画,有点像android的共享动画;设置成screen的话,头部是跟随这新的页面重新出现。 |
cardStyle | 可以给页面设置style |
transitionConfig | 一个函数类型,可以用来配置转厂动画 |
onTransitionStart | 函数类型,动画开始后的回调 |
onTransitionEnd | 函数类型,动画结束时的回调 |
Screen Navigation Options
属性 | 作用 |
---|---|
title | string类型,如果设置了它,如果headerTitle或tabBarBabel没有设置的话,将默认会使用这个值 |
header | React Eelement或 是一个参数是HeaderProps返回Rect Element类型的函数类型。它用来显示为header,设置null的话,可以隐藏header |
headerTitle | string 或者 React Element类型,用来设置header,默认显示的 title |
headerBackTitle | string 类型,用来设置在ios上显示黑色按钮,设置null不显示,默认是title |
headerTruncatedBackTitle | string 类型, 用来设置黑色按钮,当headerBackTitle 没有充满屏幕的时候。 |
headerRight | React Element类型,用来在Header右边添加控件 |
headerLeft | React Element类型,用来在Header左边添加控件 |
headerStyle | 设置header的样式 |
headerTitleStyle | 用来设置title组件的样式 |
headerBackTitleStyle | 用来设置黑色Title的样式 |
headerTintColor | 用来设置header的颜色 |
headerPressColorAndroid | 用来设置涟漪效果的颜色,android>5.0有效 |
gesturesEnabled | 开启的话,你可以用手势 关闭页面,ios默认是true,Android默认是false。我用android机开启该选项,不知道用手势什么关~~。这TM就尴尬了~ |
Navigator Props
我们创建StackNavigator的时候,如果想从外部给屏幕组件传入扩展的属性,可以使用
* screenProps 给StackNavigator传入该属性,这个属性将继续传递StackNavigator中的screens,例如:
const SomeStack = StackNavigator({
// config
});
<SomeStack
screenProps={/* 这个属性将传递给屏幕组件,在屏幕组件使用 this.props.screenProps就可以访问 */}
/>
注意这个键一定要是 screenProps,别的可不行哟。
TabNavigator
用这个可以实现几个屏幕之间相互切换,(类似于android原生,TabLayout+Fragment 页面切换那种效果)。
使用
/**
* Created by blueberry on 6/15/2017.
*/
import React, {Component} from 'react';
import {StyleSheet, AppRegistry, View, Button, Image,} from 'react-native';
import {TabNavigator, TabBarBottom, TabView, TabBarTop} from 'react-navigation';
class HomeScreen extends Component {
static navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({tintColor}) => (<Image source={require('./img/chat_online_talk.png')}
style={[styles.icon, {tintColor: tintColor}]}
/>),
};
render() {
return (
<Button title="Go to Notification" onPress={() => this.props.navigation.navigate('Notifications')}/>
);
}
}
class NotificationScreen extends Component {
static navigationOptions = {
tabBarLabel: 'Notifications',
tabBarIcon: ({tintColor}) => (<Image source={require('./img/notification.png')}
style={[styles.icon, {tintColor: tintColor}]}
/>),
// 也可以是其他React Element,
// tabBarIcon: ({tintColor}) => (<Button title="按钮" onPress={() => {
// }}/>),
}
;
render() {
return (
<Button title="Go back home" onPress={() => this.props.navigation.goBack()}/>
);
}
}
var styles = StyleSheet.create({
icon: {width: 26, height: 26}
});
const App = TabNavigator(
{
Home: {screen: HomeScreen},
Notifications: {screen: NotificationScreen}
},
{
tabBarOptions: {
//激活的tab tint颜色
activeTintColor: '#e91e63',
//没有激活的tab tint颜色
inactiveTintColor: 'black',
//大写转换
upperCaseLabel: true,
//显示icon
showIcon: true,
},
// android默认是TabBarTop,ios默认是TabBarBottom,
tabBarComponent: TabBarBottom,
// 可以为 top,bottom,用来决定TabBar放置的位置
tabBarPosition: 'bottom',
//设置是否可以滑动
swipeEnabled: true,
//切换时是否欧动画效果
animationEnabled: false,
// 是否懒渲染tabs
lazy: false,
//第一个被加载的路由名称
initialRouteName: 'Home',
//路由名称数组
order: ['Home', 'Notifications'],
paths: {Home: 'home', Notifications: 'Notifications'},
backBehavior: true,
}
);
AppRegistry.registerComponent('Project05', () => App);
Api 定义
TabNavigator(RouteConfigs,TabNavigatorConfigs)
RouteConfigs
这个和StackNavigator的RouteConfigs一样,上文已经讲过,用来设置路由信息。
TabNavigatorConfig
属性 | 作用 |
---|---|
tabBarComponent | 用来设置tab bar的组件,ios默认是TabBarBottom,android默认是TabBarTop |
tabBarPosition | 用来设置tabBar的位置,可以为 ‘top’ 或者’bottom’ |
swipeEnable | 用来设置是否可以滑动切换 |
animateEnable | 用来设置是否有动画效果 |
lazy | 用来设置是否“懒渲染”tabbar |
tabBarOption | 用来设置tabBar的一些属性,颜色、样式等等,下文将要介绍 |
initialRouteName | 初始化路由的名称 |
order | 路由名称数组 |
paths | 提供一个map,可以路由对应的path |
backBehavior | 如果设置为true,那么上面的例子,在第二个页面,按返回将不能反会到前一个页面,也就是是this.props.navigation.goBack()’不会起作用 |
TabBarBottom 的 tabBarOptions 设置
属性 | 作用 |
---|---|
activeTintColor | 激活的tab的tint 颜色,tint颜色值,icon和Label的颜色 |
activeBackgroundColor | 激活tab的背景颜色 |
inactiveTintColor | 没被激活的tint颜色 |
inactiveBackgroundColor | 没被激活的tab的背景色 |
showLabel | 是否显示label,默认是true |
style | tab bar的样式 |
labelStyle | label的样式 |
tabStyle | tab的样式 |
TabBarTop 的 tabBarOptions设置
属性 | 作用 |
---|---|
activeTintColor | 激活的tab的tint 颜色,tint颜色值,icon和Label的颜色 |
inactiveTintColor | 没被激活的tint颜色 |
showIcon | 是否显示icon,默认是false |
showLabel | 是否显示label,默认是true |
upperCaseLabel | 是够开启大写转换,默认是true |
pressColor | 按压颜色,涟漪效果,andorid>5.0有效 |
pressOpacity | 按压颜色,透明度变换,android<5.0 和ios可用。 |
scrollEnabled | tabs是够可以滑动 |
tabStyle | tab的样式 |
indicatorStyle | 底部指示器的样式 |
labelStyle | label的样式 |
iconStyle | icon的样式 |
style | tab bar的样式 |
举个栗子:
tabBarOptions: {
labelStyle: {
fontSize: 12,
},
tabStyle: {
width: 100,
},
style: {
backgroundColor: 'blue',
},
}
Screen Navigation Options
属性 | 作用 |
---|---|
title | 标题,如果headerTitle,和tabBarLabel,不设置的话,就默认是title |
tabBarVisible | 决定隐藏还是显示tab bar |
tabBarIcon | 可以是一个React Eclement,或者是一个参数为{focused:boolean,tintColor:string} 返回Rect Element的函数,用来显示在Tab Bar上 |
tabBarLabel | string类型,或者React Element类型,或者是参数为{focused:boolean,tintColor:string} 返回React Element的函数 |
Navigator Props
我们创建TabNavigator的时候,如果想从外部给屏幕组件传入扩展的属性,可以使用
* screenProps 给TabNavigator传入该属性,这个属性将继续传递TabNavigator中的screens。这个和StackNavigator的用法一样,可以参考上文。
DrawerNavigator
这个导航是个抽屉效果,就是类似于QQ那种左滑菜单
使用
/**
* Created by blueberry on 6/15/2017.
*/
import React, {Component} from 'react';
import {AppRegistry, StyleSheet, View, Button, Image, ScrollView} from 'react-native';
import {DrawerNavigator, DrawerItems} from 'react-navigation';
class HomeScreen extends Component {
static navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({tintColor}) => (<Image
style={[styles.icon, {tintColor: tintColor}]}
source={require('./img/chat_online_talk.png')}/>),
}
render() {
return (
<View>
<Button title="Go to notifications" onPress={() => this.props.navigation.navigate('Notifications')}/>
<Button title="打开抽屉" onPress={() => this.props.navigation.navigate('DrawerOpen')}/>
<Button title="关闭抽屉" onPress={() => this.props.navigation.navigate('DrawerClose')}/>
</View>
);
}
}
class NotificationScreen extends Component {
static navigationOptions = {
drawerLabel: 'notifications',
drawerIcon: ({tintColor}) => (<Image
style={[styles.icon, {tintColor: tintColor}]}
source={require('./img/notification.png')}/>),
}
render() {
return (
<Button title="Go back home" onPress={() => this.props.navigation.goBack()}/>
);
}
}
const App = DrawerNavigator(
{Home: {screen: HomeScreen}, Notifications: {screen: NotificationScreen}},
//一下是DrawerNavigator 的配置
{
// 设置宽度
drawerWidth: 300,
// 设置从右边拉出,还是左边拉出
drawerPosition: 'left',
//默认的的值是 DrawerItems,我们也可以自己配置组件
contentComponent: props => <ScrollView
style={{borderWidth: 1, borderColor: 'red'}}><DrawerItems {...props}/></ScrollView>,
contentOptions: {
items: ['Home', 'Notification'],
activeItemKey: 'key',
activeTintColor: '#ff863f',
activeBackgroundColor: '#d0caff',
inactiveTintColor: '#000000',
inactiveBackgroundColor: '#fffcf8',
//这个设置了没起作用,android,api 0.45
onItemPress: (route) => {
console.log('TAG' + JSON.stringify(route))
},
style: null,
labelStyle: null,
},
// initialRouteName:'Notifications',
}
)
;
var styles = StyleSheet.create({
icon: {width: 26, height: 26}
});
AppRegistry.registerComponent('Project05', () => App);
可以使用一下操作,打开或关闭抽屉
this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer
Api定义
DrawerNavigator(RouteConfigs, DrawerNavigatorConfig)
RouteConfigs
这个和StackNavigator一样,可以参考上文。
DrawerNavigatorConfig
属性 | 作用 |
---|---|
drawerWidth | 抽屉的宽度 |
drawerPosition | 枚举值可以为‘left’或’rigt’表示抽屉是在左边还是右边 |
contentComponent | 可以自定义显示drawer item的组件,默认是实现是DrawerItem |
contentOptions | drawer 内容的一些设置,背景颜色,tint颜色等等,下文将会讲到 |
DrawerItems 的contentOptions
属性 | 作用 |
---|---|
items | 路由的数组 |
activeItemKey | 正在活动的路由的key |
activeTintColor | 正在活动的 item tint 颜色 |
activeBackgroundColor | 正在活动的item的 背景颜色 |
inactiveTintColor | 不在活动的item的 tint颜色 |
inactiveBackgroundColor | 不在活动的item 的背景颜色 |
onItemPress(route) | 设置一个函数,item被按下时,这个函数将被调用 |
style | Dawer的样式 |
labelStyle | label的样式 |
Screen Navigation Options
属性 | 作用 |
---|---|
title | 标题,如果headerTitle,和tabBarLabel,不设置的话,就默认是title |
tabBarVisible | 决定隐藏还是显示tab bar |
tabBarIcon | 可以是一个React Eclement,或者是一个参数为{focused:boolean,tintColor:string} 返回Rect Element的函数,用来显示在Tab Bar上 |
tabBarLabel | string类型,或者React Element类型,或者是参数为{focused:boolean,tintColor:string} 返回React Element的函数 |
Navigator Props
这个跟StackNavigator 和 TabNavigator的方式一样,可以参考上文。
Screen中的 Navigation 属性
每个Screen都会接收这样一个属性,它其中包含了以下对象:
- navigate 用来跳转到其它页面。
- state 屏幕当前的 state/routes 里面包含有路由信息和参数信息。
- setParams 可以用来改变参数信息。
- goBack 用来关闭当前的活动页面,并返回。
dispatch 给路由发送一个action。
下面来逐个讲解喽~
navigate
它的函数形式为:
navigate(routeName, params, action)
- routeName 要跳转的页面路由名称。
- params 参数信息。
- action 高级用法~,逐个子 action运行在child路由,如果要跳转的页面也是一个Navigator的话。
state
页面可以通过 this.props.navigation.state
获得,它的形式为:
{
// 路由的名称
routeName: 'profile',
//唯一的id
key: 'main0',
// 参数
params: { hello: 'world' }
}
setParams
改变路由的参数
例如:
class ProfileScreen extends React.Component {
render() {
const {setParams} = this.props.navigation;
return (
<Button
onPress={() => setParams({name: 'Lucy'})}
title="Set title name to 'Lucy'"
/>
)
}
}
goBack
关闭当前页面,并返回
示例:
class HomeScreen extends React.Component {
render() {
const {goBack} = this.props.navigation;
return (
<View>
<Button
onPress={() => goBack()}
title="Go back from this HomeScreen"
/>
<Button
onPress={() => goBack(null)}
title="Go back anywhere"
/>
<Button
onPress={() => goBack('screen-123')}
title="Go back from screen-123"
/>
</View>
)
}
}
dispatch
给路由发送一个action。用个栗子(没有什么比看代码来的简单明了了)。
/**
* Created by blueberry on 6/15/2017.
*/
import React, {Component} from 'react';
import {AppRegistry, View, Button, Image, Text} from 'react-native';
import {NavigationActions, TabNavigator} from 'react-navigation';
class MainScreen extends Component {
render() {
return (
<View>
<Button title="跳转到Child页面" onPress={() => this.props.navigation.navigate('Child')}/>
<Text>{this.props.navigation.state.params ? this.props.navigation.state.params.title : ''}</Text>
</View>
);
}
}
class ChildScreen extends Component {
render() {
const navigationActions = NavigationActions.navigate({
routeName: 'Home',
params: {title: 'blueberryTitle'}
});
return (
<View>
<Button title="返回" onPress={() => this.props.navigation.goBack()}/>
<Button title="返回Home显示title" onPress={() => this.props.navigation.dispatch(navigationActions)}/>
</View>
);
}
}
const App = TabNavigator(
{Home: {screen: MainScreen,}, Child: {screen: ChildScreen}}
);
AppRegistry.registerComponent('NavigationUsage', () => App);
上面核心代码:
const navigationActions = NavigationActions.navigate({
routeName: 'Home',
params: {title: 'blueberryTitle'}
});
this.props.navigation.dispatch(navigationActions)
NavigationActions创建了一个acionts,然后使用dispatch去执行了,上面的执行效果就是,挑战到了Home页面,并传入了参数{title:'blueberryTitle'}
。
Naviation Actions
上文已经简单延时了navigation.dispatch()
的用法。
它支持的action有:
- navigate 跳转到其他路由
- Rest 使用一个新的State替换当前的state。
- Back 返回到前一个状态
- Set Params 给你个路由设置 参数。
- Init 如果state没有定义,使用它初始化第一个状态。
Navigate
用法:
import { NavigationActions } from 'react-navigation'
const navigateAction = NavigationActions.navigate({
routeName: 'Profile',
params: {},
action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
})
this.props.navigation.dispatch(navigateAction)
属性 | 作用 |
---|---|
routeName | 路由名称 |
params | 参数 |
action | 高级用法,如果他要跳转的路由也是一个Navigator,用可以用来设置那个Navigator的action |
Reset
用来重新设置路由记录
const resetAction = NavigationActions.reset({
index: 1,
actions: [
NavigationActions.navigate({ routeName: 'Profile'}),
NavigationActions.navigate({ routeName: 'Settings'})
]
})
this.props.navigation.dispatch(resetAction
注意 index的值 必须在0 - actions.lenght的范围内,不能越界,指定当前在栈中的位置。
Back
使用方法:
const backAction = NavigationActions.back({
key: 'Profile'
})
this.props.navigation.dispatch(backAction)
key为路由的唯一身份,但是我设置了以后,使用this.props.navigation.dispatch()
没有效果,不设置的话,可以返回,我使用的Andorid机测试。
SetParams
const setParamsAction = NavigationActions.setParams({
params: { title: 'Hello' },
key: 'screen-123',
})
this.props.navigation.dispatch(setParamsAction)
- parmas 为参数
- key 为要修改的路由的身份
Screen Navigation Options
配置navigatinOptions
可以用2中方法来设置 navigationOptions
静态配置
示例:
class MyScreen extends React.Component {
static navigationOptions = {
title: 'Great',
};
...
动态配置
示例:
class ProfileScreen extends React.Component {
static navigationOptions = ({ navigation, screenProps }) => ({
title: navigation.state.params.name + "'s Profile!",
headerRight: <Button color={screenProps.tintColor} {...} />,
});
这个函数接收的参数为props,props参数中包含 navigation,screenProps ,navigationOptions。返回值用来决定设置的navigationOpiotns。
参数的结构如下:
+ Props
- navigation
- screenProps
- navigationOptions
一般的Navigation Options 配置方法
class MyScreen extends React.Component {
static navigationOptions = {
title: 'Great',
};
...
其他的配置方法
可以在配置路由的时候设置:
const SimpleApp = StackNavigator({
// 使用 header:null 去掉StackNavigator的导航栏头部
Home: {screen: MainScreenNavigator, navigationOptions: ({navigation}) => ({header: null}),},
Chat: {
screen: ChatScreen,
//路径,user为可以接受的参数
path: 'chat1/:user',
}
},{})
还可以在Navigation 配置中设置
const App = StackNavigator(
/**
* 路由配置
*/
{
Home: {screen: MainScreen},
Profile: {screen: Profile, navigationOptions: {headerRight: null}},
},
/**
* StackNavigator配置,也可以省略。
*/
{
navigationOptions: {headerRight: <Text>右边Header</Text>},
}
);
示例代码地址
https://github.com/blueberryCoder/RNDemo/tree/master/NavigationUsage
参考
https://reactnavigation.org/docs/intro/headers