React Native导航器Navigator
使用导航器可以让你在应用的不同场景(页面)间进行切换。导航器通过路由对象来分辨不同的场景。利用renderScene方法,导航栏可以根据指定的路由来渲染场景。可以通过configureScene属性获取指定路由对象的配置信息,从而改变场景的动画或者手势。——以上内容摘录自React Native中文网
一、Navigator的属性
configureScene
可选的函数,用来配置场景动画和手势。会带有两个参数调用,一个是当前的路由,一个是当前的路由栈。然后它应当返回一个场景配置对象。
使用方式:
(route, routeStack) => Navigator.SceneConfigs.FloatFromRight
切换效果有:
Navigator.SceneConfigs.PushFromRight (默认)
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
initialRoute
类类型的属性,定义启动时加载的路由。路由是导航栏用来识别渲染场景的一个对象。initialRoute必须是initialRouteStack中的一个路由。initialRoute默认为initialRouteStack中最后一项。
initialRouteStack
类类型的属性,用来在Navigator组件初加载时提供导航路径。如果没有向Navigator组件提供initialRoute属性,就必须提供initialRouteStack属性;如果提供了initialRoute但没有提供initialRouteStack,那么React Native会生成一个只有initialRoute元素的数据作为initialRouteStack。
navigationBar
该属性返回一个可以渲染的节点,这个节点可以用作所有界面的通用导航栏。当开发者决定使用navigationBar来进行导航时,大部分应用界面的导航栏都具有相同的格式(相同大小的按钮、标题栏等),只是按钮的图片或者标题栏中的文字各有不同。
给Navigator组件指定导航栏的示例如下:
navigationBar = {
<Navigator.NavigationBar routeMapper={ navigationBarRouteMapper}/>
}
Navigator.NavigationBar是一个可显示的React Native组件,它必须有一个routeMapper属性。开发者必须将一个对象指定给routeMapper属性。这个对象可以有三个成员变量:LeftButton、RightButton、Title。其中,Title成员变量必须有。这三个成员变量要求都是函数类型的,Navigator组件渲染导航栏时,使用这三个函数的返回值渲染导航栏的对应区域。
每个函数可以接收4个参数。示例:
LeftButton: function( route, navigator, index, navState)
在三个成员函数返回的可渲染节点的样式中设置三个区域的大小。这三个函数返回的可渲染节点就是三个区域中显示的内容。
不同的页面需要控制这三个区域中显示不同的内容,开发者需要将不同页面待显示的不同内容(文字、图片)通过route传入这三个函数中,然后这三个函数从route的成员变量中去处传入的供显示的不同内容,最后渲染显示。
对按钮或输入框的处理,通常都需要调用父组件的函数,这就需要将这个父组件的函数以某种方式传入routeMapper属性中。开发者无法直接给routeMapper属性再传值,但是可以放在route中,由Natigator组件在渲染时交给routeMapper属性。而route中的成员变量,都是由开发者提供的,并且对每个事件只能提供一个回调函数,准确地说,是最近一次提供的回调函数会覆盖上一次提供的回调函数。
Navigator
提供从父导航器获得的导航器对象。
onDidFocus
每当导航切换完成或初始化之后,调用此回调,参数为新场景的路由。
React native鼓励开发者使用navigationContext.addListener(‘didfocus’,callback)事件监听器来实现相同的功能。
onWillFocus
会在导航切换之前调用,参数为目标路由。
React native鼓励开发者使用navigationContext.addListener(‘willfocus’,callback)事件监听器来实现相同的功能。
renderScene
必要参数。用来渲染指定路由的场景。调用的参数是路由和导航器。
sceneStyle
指定的样式将被应用到每一个切换的场景中。
二、导航器的函数
getCurrentRoutes()
获取当前栈里的路由,也就是push进来,没有pop掉的那些。
jumpBack()
退回到上一个界面而不卸载当前界面。
jumpForward()
沿界面路径向前跳一个界面而不卸载当前界面。
jumpTo(route)
跳转到某个界面而不卸载任何界面。
push(route)
导航组件在路径列表最前端添加一个新的界面,并马上跳转至这个界面。
pop()
导航器退回一个界面并卸载原界面。
replace(route)
用一个新的路由替换掉当前场景。
replaceAtIndex(route, index)
使用一个新的界面替代路径表中的第index个界面,但不改变当前显示界面。
replacePrevious(route)
将当前导航路径的上一个界面使用指定的界面替代。
resetTo(route)
跳转到新的场景,并且重置整个路由栈。
immediatelyResetRouteStack(routeStack)
使用给定的路径表替换当前的路径列表。
popToRoute(route)
导航器回退到指定的界面,并且将这个过程中回退过的界面都卸载。
popToTop()
导航器回退到的第一个场景,卸载掉所有的其他场景。
三、Navigator传值
实现的效果为:第一个界面向第二个界面传值,在第二个界面中改变第一个界面的显示内容。
index.android.js
1 import React from 'react'; 2 import { 3 View, 4 Navigator, 5 AppRegistry 6 } from 'react-native'; 7 import FirstPageComponent from './js/FirstPageComponent'; 8 export default class SampleComponent extends React.Component { 9 render() { 10 let defaultName = 'FirstPageComponent'; 11 let defaultComponent = FirstPageComponent; 12 return ( 13 <Navigator 14 initialRoute={{ name: defaultName, component: defaultComponent }} 15 configureScene={(route) => { 16 return Navigator.SceneConfigs.HorizontalSwipeJumpFromRight; 17 }} 18 renderScene={(route, navigator) => { 19 let Component = route.component; 20 return <Component {...route.params} navigator={navigator} /> 21 }} 22 /> 23 ); 24 } 25 } 26 27 AppRegistry.registerComponent('listen1', () => SampleComponent);
第一个界面
1 import React from 'react'; 2 import { 3 View, 4 Navigator, 5 TouchableOpacity, 6 Text, 7 } from 'react-native'; 8 9 import SecondPageComponent from './SecondPageComponent'; 10 11 export default class FirstPageComponent extends React.Component { 12 13 constructor(props) { 14 super(props); 15 16 this.state = { 17 id: 2, 18 user: null, 19 } 20 } 21 22 23 _pressButton() { 24 let _this = this; 25 const { navigator } = this.props; 26 if(navigator) { 27 navigator.push({ 28 name: 'SecondPageComponent', 29 component: SecondPageComponent, 30 params: { 31 id: this.state.id, 32 //从SecondPageComponent获取user 33 getUser: function(user) { 34 _this.setState({ 35 user: user 36 }) 37 } 38 } 39 }); 40 } 41 } 42 43 render() { 44 if( this.state.user ) { 45 return( 46 <View> 47 <Text>用户信息: { JSON.stringify(this.state.user) }</Text> 48 </View> 49 ); 50 }else { 51 return( 52 <View> 53 <TouchableOpacity onPress={this._pressButton.bind(this)}> 54 <Text>查询ID为{ this.state.id }的用户信息</Text> 55 </TouchableOpacity> 56 </View> 57 ); 58 } 59 60 } 61 }
第二个界面
1 const USER_MODELS = { 2 1: { name: 'mot', age: 23 }, 3 2: { name: '晴明大大', age: 25 } 4 }; 5 6 import React from 'react'; 7 import { 8 View, 9 Navigator, 10 TouchableOpacity, 11 Text, 12 } from 'react-native'; 13 14 import FirstPageComponent from './FirstPageComponent'; 15 16 export default class SecondPageComponent extends React.Component { 17 18 constructor(props) { 19 super(props); 20 this.state = { 21 id: null 22 } 23 } 24 25 componentDidMount() { 26 //这里获取从FirstPageComponent传递过来的参数: id 27 this.setState({ 28 id: this.props.id 29 }); 30 } 31 32 _pressButton() { 33 const { navigator } = this.props; 34 35 if(this.props.getUser) { 36 let user = USER_MODELS[this.props.id]; 37 this.props.getUser(user); 38 } 39 40 if(navigator) { 41 navigator.pop(); 42 } 43 } 44 45 render() { 46 return( 47 <View> 48 <Text>获得的参数: id={ this.state.id }</Text> 49 <TouchableOpacity onPress={this._pressButton.bind(this)}> 50 <Text>点我跳回去</Text> 51 </TouchableOpacity> 52 </View> 53 ); 54 } 55 }
在第二个界面中修改第一个界面的原理是:在第一个界面中声明一个方法,可以更改其state。我们知道,state发生改变,界面就会重新渲染。在传值的时候,将该方法作为一个属性传给第二个界面。在第二个界面中执行该方法,就重新渲染了第一个界面。只不过此时的第一界面没有在屏幕上。当第二个界面卸载(pop)后,返回第一个界面,就看到了更改后的第一个界面。