移动端有个常用的UI控件导航控制器,在RN里面就是Navigator控件。今天在说Navigator之前先说个不是很恰当的比喻用来解释Navigator的工作流程:平时在看电视的时候我们都会用遥控器切换电视机播放的频道,在遥控器上面你不仅可以使用上一个、下一个这种按键来切换频道也可以手动输入频道数来跳转到指定的频道,在我看来这个过程就是使用navigator进行页面跳转的过程。至于你跳转到指定频道后电视机播放的内容那是由这个频道接收到的电磁波包含的信息决定的,指定频道接收的电磁波可以类比指定页面绑定的路由,页面将显示什么内容都是根据route这个路由对象包含的内容决定的。接下来看看演示的效果:
我们先定义一组路由信息:
const routes = [
{message:'第一页',index:0,component:FirstPage},
{message:'第二页',index:1,component:SecondPage},
{message:'第三页',index:2,component:ThirdPage}
];
routes里面的每个元素就是一个路由,这个路由里面包含了页面显示所需要的信息,message我们规定它代表了页面的标题,index我们将所有的页面编号用于识别,component我们规定它表示了这个页面将要展示的具体内容。注意,路由里面包含的信息都是可以自己定义的。
Navigator里面有一些常用的属性:
initialRoute 这个属性可以用来指定初始化页面,你可以传入一个路由用来初始化。
initialRouteStack 这个属性可以传入一个路由数组来表示将要显示的一系列页面,设置了这个后Navigator会将这些路由都一次性的压入堆栈。
renderScene当前渲染的页面,它的参数是一个函数,简单看下官方的说明
在renderScene这个属性里面我们可以很方便的获取到两个主要的值:
route和navigator,这样我们就可以显示我们想要的任何内容了也可以跳转的其他页面离开当前页面了
/**
* Required function which renders the scene for a given route. Will be
* invoked with the `route` and the `navigator` object.
*
* ```
* (route, navigator) =>
* <MySceneComponent title={route.title} navigator={navigator} />
* ```
*/
renderScene: PropTypes.func.isRequired,
style 是navigator的样式
configureScene这个属性是用来配置页面跳转动画和手势的,常用的动画手势如下
- Navigator.SceneConfigs.PushFromRight (default)
- Navigator.SceneConfigs.FloatFromRight
- Navigator.SceneConfigs.FloatFromLeft
- Navigator.SceneConfigs.FloatFromBottom
- Navigator.SceneConfigs.FloatFromBottomAndroid
- Navigator.SceneConfigs.FadeAndroid
- Navigator.SceneConfigs.HorizontalSwipeJump
- Navigator.SceneConfigs.HorizontalSwipeJumpFromRight
- Navigator.SceneConfigs.VerticalUpSwipeJump
- Navigator.SceneConfigs.VerticalDownSwipeJump
navigationBar 这个属性是用来设置导航栏的,我们可以设置导航栏的左右按钮和标题,接下来我们看看部分代码:
return(
<Navigator
initialRoute={routes[0]}
initialRouteStack = {routes}
renderScene={(route,navigator) =>
<route.component route={route} navigator={navigator} routes={routes}/>
}
style={styles.navigator}
configureScene = {(route) => {
if (route.index === 0) {
return Navigator.SceneConfigs.HorizontalSwipeJump
}
if (route.index === 1) {
return Navigator.SceneConfigs.PushFromRight
}
if (route.index === 2) {
return Navigator.SceneConfigs.FloatFromBottom
}
}}
navigationBar={
<Navigator.NavigationBar
routeMapper={{
LeftButton: (route, navigator, index, navState) =>
{
if(route.index === 0) {
return null;
}else {
return(
<TouchableHighlight onPress={() => {
navigator.jumpBack() //不能是当前栈里面的第一个页面
}}>
<Text>back</Text>
</TouchableHighlight>
)
}
},
RightButton: (route, navigator, index, navState) =>
{
if(route.index === 2) {
return null;
}else {
return(
<TouchableHighlight onPress={() => {
let routes = navigator.getCurrentRoutes()
if (routes.length < 1) {
return;
}
if (routes.pop().index !== route.index) {
navigator.jumpForward() //不能是当前栈里面的最后一个页面
}
}}>
<Text>forward</Text>
</TouchableHighlight>)
}
},
Title: (route, navigator, index, navState) =>
{ return (<Text style={styles.Title}>{route.message}</Text>); },
}}
style={{backgroundColor: 'green'}}
/>
}
>
</Navigator>
)
上面的导航栏的左右按钮分别是返回到上一个页面和跳转到下一个页面,要注意的是这里的跳转都是在路由栈里的路由间跳转的,所以在执行navigator.jumpForward()之前要判断当前页面不能是栈里面的最后一个页面,在执行navigator.jumpBack() 之前也要判断当前页面不能是栈里面的第一个页面。
下面我们简单介绍第二个页面,其他两个跟第二个页面类似:
class SecondPage extends Component {
render () {
return(
<View style={{backgroundColor:'burlywood',flex:1}}>
<TouchableHighlight
onPress={() => {
this.props.navigator.push(this.props.routes[this.props.route.index+1])
}
}>
<Text style={[styles.text,{fontSize:15}]}>第二页push</Text>
</TouchableHighlight>
<TouchableHighlight
onPress={() => {
this.props.navigator.pop()
}
}>
<Text style={[styles.text,{fontSize:15}]}>第二页pop</Text>
</TouchableHighlight>
</View>
)
}
}
在每个页面里面我们都可以获取到navigator、route这两个关键信息,这样我们就可以随意在当前页面跳转到指定的页面了。在这里要注意的是pop() push()这一组跳转动作和jumpBack() jumpForward()这一组跳转动作的区别在于前一组的跳转会改变路由栈 后一组不会。
以上代码都已经上传gitub ,源码下载