前面三篇文章我们分别介绍了React基础,Flexbox模型和手势响应,今天我们介绍任何软件,系统都很重要的导航部分。
Navigator
对于Android开发人员来讲(IOS猿请忽略),Android页面之间的跳转是由工作栈维护的,进入一个页面,一般的是入栈,而退出一个页面,就意味着出栈。我们在开发app的时候,之所以没有感觉到出栈入栈,是因为Android将这些都封装好了。React Native则比较粗暴,你从它页面的跳转方法就可以明显的看出,它是由栈实现的,归结到组件的话就是Navigator组件(IOS有NavigatorIOS组件,相较于Navigator,效率更高)。下面来看一个简单的例子:
import FirstPageComponent from './FirstPageComponent';
class demoReact extends Component {
render() {
let defaultName = 'FirstPageComponent';
let defaultComponent = FirstPageComponent;
let defaultTitle = "First Page";
return (
<Navigator
initialRoute={{
name: defaultName,
component: defaultComponent,
title: defaultTitle,
}}
configureScene={(route) => {
return Navigator.SceneConfigs.VerticalDownSwipeJump;
}}
renderScene={(route, navigator) => {
let Component = route.component;
return <Component {...route.params} navigator={navigator} />
}}
/>
);
}
};
其中:
-
initialRoute
:定义了启动加载时的路由,上面的示例定义了组件名称,组件和页面的标题。 -
configureScene
:定义了页面切换时的过渡动画,可选的值有: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
-
renderScene
:此方法时必要参数。用来渲染指定路由的场景。调用的参数是路由和导航器。
FirstPageComponent.js的代码如下:
import React from 'react';
import {
View,
Navigator,
TouchableOpacity,
Text,
StyleSheet
} from 'react-native';
import SecondPageComponent from './SecondPageComponent';
export default class FirstPageComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
id:1,
user:null,
};
}
componentDidMount() {
}
_pressButton() {
const { navigator } = this.props;
if(navigator) {
navigator.push({
name: 'SecondPageComponent',
component: SecondPageComponent,
title:'Second Page',
params:{
id:this.state.id,
getUser: (user) => {
this.setState({
user: user
})
}
}
})
}
}
render() {
if(this.state.user) {
return(
<View style={styles.container}>
<Text>用户信息: { JSON.stringify(this.state.user) }</Text>
</View>
);
}else {
return(
<View style={styles.container}>
<TouchableOpacity onPress={this._pressButton.bind(this)} style={styles.userLayout}>
<Text >查询ID为{ this.state.id }的用户信息</Text>
</TouchableOpacity>
</View>
);
}
}
}
var styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
marginTop:100,
},
userLayout:{
borderWidth:1,
borderColor:'black',
padding:10,
}
});
SecondPageComponent.js的代码
import React from 'react';
import {
View,
Navigator,
Text,
TouchableOpacity,
StyleSheet
} from 'react-native';
import FirstPageComponent from './FirstPageComponent';
const USER_MODELS = {
1: { name: 'fyales一号', age: 23 },
2: { name: 'fyales二号', age: 25 }
};
export default class SecondPageComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
id:null,
title:"Second Page",
};
}
componentDidMount(){
this.setState({
id:this.props.id,
title:this.props.title,
});
}
_pressButton() {
const { navigator } = this.props;
if(this.props.getUser) {
let user = USER_MODELS[this.props.id];
this.props.getUser(user);
}
if(navigator) {
//出栈
navigator.pop();
}
}
render() {
return (
<View style = {styles.container}>
<Text>获得的参数: id={ this.state.id }</Text>
<TouchableOpacity onPress={this._pressButton.bind(this)} style={styles.backLayout}>
<Text>返回</Text>
</TouchableOpacity>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
marginTop:100,
},
backLayout:{
borderWidth:1,
borderColor:'black',
padding:10,
}
});
我们可以先看看FirstPageComponent.js的跳转逻辑,navigator.push()
方法就是将SecondPage入栈,同样的,我们通过定义组件名称,组件来找到相应的文件,并将下一个页面需要展示的title传到下一个页面。而且,我们通过params参数传了一些数据和一个回调函数给下一个页面。这里需要注意的是,states存储的一般的是当前页面的值,而props存储的一般是其他页面传给本页面的值。
在我们从FirstPage跳到SecondPage之后,再点击返回按钮的时候,_pressButton
方法首先执行了第一个页面的回调方法,从而刷新了第一个页面的状态,同时第二个页面出栈,返回到了第一个页面。
除了最基本的push
方法和pop
方法,navigator还有许多其他方法进行导航:
-
getCurrentRoutes()
:获取当前栈里的路由,也就是push进来,没有pop掉的那些。 -
jumpBack()
:跳回之前的路由,当然前提是保留现在的,还可以再跳回来,会给你保留原样。 -
jumpForward()
:上一个方法不是调到之前的路由了么,用这个跳回来就好了。 -
jumpTo(route)
: 跳转到已有的场景并且不卸载。 -
push(route)
:跳转到新的场景,并且将场景入栈,你可以稍后跳转过去 -
pop()
:跳转回去并且卸载掉当前场景 -
replace(route)
:用一个新的路由替换掉当前场景 -
replaceAtIndex(route, index)
:替换掉指定序列的路由场景 -
replacePrevious(route)
: 替换掉之前的场景 -
resetTo(route)
:跳转到新的场景,并且重置整个路由栈 -
immediatelyResetRouteStack(routeStack)
:用新的路由数组来重置路由栈 -
popToRoute(route)
:pop到路由指定的场景,在整个路由栈中,处于指定场景之后的场景将会被卸载。 -
popToTop()
:pop到栈中的第一个场景,卸载掉所有的其他场景。
navigationBar(导航栏)
同样的,为了实现类似Android导航栏的功能,React Native提供了NavigationBar(类似于Android的Toolbar,不过个人觉得不太好用,建议用第三方库),加了NavigationBar的index.android.js代码如下:
import React, {
Component,
} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Navigator,
TouchableOpacity
} from 'react-native';
import FirstPageComponent from './FirstPageComponent';
class demoReact extends Component {
render() {
let defaultName = 'FirstPageComponent';
let defaultComponent = FirstPageComponent;
let defaultTitle = "First Page";
return (
<Navigator
initialRoute={{
name: defaultName,
component: defaultComponent,
title: defaultTitle,
}}
configureScene={(route) => {
return Navigator.SceneConfigs.FadeAndroid;
}}
renderScene={(route, navigator) => {
let Component = route.component;
return <Component {...route.params} navigator={navigator} />
}}
navigationBar={
<Navigator.NavigationBar
routeMapper={NavigationBarRouteMapper}
style={styles.navBar}
/>
}
/>
);
}
};
var NavigationBarRouteMapper = {
LeftButton: function(route, navigator, index, navState) {
if (index === 0) {
return null;
}
return (
<View style={styles.navBarLeftButton}>
<TouchableOpacity
onPress={() => navigator.pop()}
>
<Text style={styles.navBarText}>
Return
</Text>
</TouchableOpacity>
</View>
);
},
RightButton: function(route, navigator, index, navState) {
return (
<View style={styles.navBarRightButton}>
<TouchableOpacity
>
<Text style={styles.navBarText}>
Next
</Text>
</TouchableOpacity>
</View>
);
},
Title: function(route, navigator, index, navState) {
return (
<View style={styles.navbarTitle}>
<Text style={styles.navBarTitleText}>
{route.title}
</Text>
</View>
);
},
};
var styles = StyleSheet.create({
navBar: {
flexDirection: 'row', //只支持column和row两种属性
flexWrap:'nowrap', //只支持wrap和nowrap两种属性
justifyContent:'center', //主轴
alignItems:'stretch', //交叉轴
backgroundColor: 'orange',
},
navBarText: {
fontSize: 16,
color:'white',
textAlign:'center',
},
navbarTitle:{
flex:2,
alignSelf:'center',
paddingTop:15,
},
navBarTitleText: {
color: 'white',
fontSize:18,
textAlign:'left',
},
navBarLeftButton: {
flex:1,
paddingLeft: 10,
paddingTop:18,
alignSelf:'flex-start',
},
navBarRightButton: {
flex:1,
paddingRight: 10,
paddingTop:18,
alignSelf:'flex-end',
},
});
AppRegistry.registerComponent('demoReact', () => demoReact);
代码中的NavigationBarRouteMapper
是导航栏路由映射器, 设置左边按钮,右边按钮和标题。完整的效果图如下:
进入第二页
点击按钮返回
第三方实现
React Native Simple Router是一款第三方导航组件。你可以通过它进行合理的视图组织。
网友评论