react-native系列(14)导航篇:页面导航StackNavigator参数及使用详解

react

react-navigation导航是RN官网推荐使用的导航插件,目前最新版本为3.x,它包括3种类型的导航:

  • StackNavigator
  • TabNavigator
  • DrawerNavigator

本篇主要介绍的是StackNavigator,假设你已经对它的用法已经有了基本的认识,或重新去官网看一下

官网地址:https://reactnavigation.org/zh-Hans/

StackNavigator嵌套

一般app的导航都只有一个导航堆栈,结构如下:

有些逻辑比较复杂的app,存在导航嵌套的情况,结构如下:

这种情况下,可以使用StackNavigator嵌套,把子导航堆栈做为根导航堆栈的其中一个页面:

// 子导航堆栈

const itemStack= createStackNavigator(

{

Screen1: { screen: Screen1}

},

...

);

// 根导航堆栈

const rootStack = createStackNavigator(

{

Screen1: { screen: itemStack}

},

...

);

createStackNavigator函数详解

createStackNavigator函数用于创建Stack导航,它包含了两个参数对象:第一个参数用来配置路由页面,第二个参数用来配置路由的其它信息。

创建时,相关参数详解如下:

const rootStack = createStackNavigator(

// 路由页面

{

Page1: { screen: PageView1 },

Page2: { screen: PageView2, params: {}} // 第二个参数params为页面入参

},

// 路由其它信息

{

initialRouteName: 'Page1', // 初始页,必须是路由配置页面中的某一个

initialRouteParams: {}, // 初始页入参

// mode: '', // 系统的页面切换动画风格,目前只有默认card和模态风格modal两种。但本人3.X版本测试结果是仅剩modal一种,一般这个配置不做设置

// headerMode: 'none' // none时表示隐藏头部的导航栏,默认情况下不做设置

// 导航栏配置

defaultNavigationOptions: {

headerStyle:{}, // 导航栏样式

headerTitle:'', // 或使用title,导航栏标题

headerTitleStyle:{}, // 导航栏标题样式

headerLeft:(<View />), // 导航栏左边如返回等的显示容器

headerRight:(<View />), // 导航栏右边如工具等的显示容器

gesturesEnabled: false, // 是否支持滑动返回手势,iOS默认支持,安卓默认关闭

},

// 自定义页面切换动画配置

transitionConfig: () => ({

// some code

})

}

);

测试代码:

import React, { Component } from 'react';

import { View, Easing, Animated } from 'react-native';

import { createStackNavigator, createAppContainer } from 'react-navigation';

import { AuthScreen, ListScreen, ItemScreen, ModalScreen } from './StackScreen';

const mainNavigator = createStackNavigator(

{

Auth: { screen: AuthScreen },

List: { screen: ListScreen, params: {defaultParam: 'this is defaultParam'}},

Item: { screen: ItemScreen }

},

{

initialRouteName: 'Auth',

initialRouteParams: { param: 'this is initParam' },

defaultNavigationOptions: {

gesturesEnabled: false

},

// 类似于微信的左右切换路由页

transitionConfig: () => ({

transitionSpec: {

duration: 300,

easing: Easing.out(Easing.poly(4)),

timing: Animated.timing,

},

screenInterpolator: sceneProps => {

const {layout, position, scene} = sceneProps;

const {index} = scene;

const Width = layout.initWidth;

//沿X轴平移

const translateX = position.interpolate({

inputRange: [index - 1, index, index + 1],

outputRange: [Width, 0, -(Width)], // Width,0指新页面进入坐标变化; 0,-(Width)是指旧页面推出坐标变化

});

//透明度

const opacity = position.interpolate({

inputRange: [index - 1, index - 0.99, index],

outputRange: [0, 1, 1],

});

return {opacity, transform: [{translateX}]};

}

})

}

);

// 根导航堆栈

const rootStack = createStackNavigator(

{

Main: { screen: mainNavigator },

Modal: { screen: ModalScreen } // modal屏操作,常会使用不同的屏间切换样式,且隐藏头部导航栏

},

{

initialRouteName: 'Main',

initialRouteParams: { defaultParam: 'defaultParam' },

mode: 'modal', // 定义跳转风格为modal

headerMode: 'none' // 隐藏该导航堆栈中的标题栏

}

);

const AppNavigatorContainer = createAppContainer(rootStack);

class StackNavigator extends Component {

render(){

return(

<View style={{flex:1}}>

<AppNavigatorContainer />

</View>

);

}

}

export default StackNavigator;

这段代码用到了导航嵌套,目的是把模态框弹窗Modal也作为导航的一部分。有些人会说也可以使用Modal组件,为什么写在这里做为导航的一个页面?因为如果不把Modal做为一个页面,那么模态框仅会弹出在导航栏下的页面容器中而不会遮挡导航栏。

导航过程效果:

NavigationOptions

navigationOptions为静态函数,写在路由页中,主要用于设置导航栏样式,配置参数:

static navigationOptions = ({ navigation }) => ({

header: null, // 为null时表示隐藏导航栏

headerStyle:{}, // 导航栏样式

headerTitle:'', // 或使用title,导航栏标题

headerTitleStyle:{}, // 导航栏标题样式

headerLeft:(<View />), // 导航栏左边如'返回'的显示容器

headerRight:(<View />), // 导航栏右边如'其它辅助功能'的显示容器

gesturesEnabled: false, // 是否支持滑动返回手势,iOS默认支持,安卓默认关闭

})

测试代码:

import React, { Component } from 'react';

import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

import PropTypes from 'prop-types';

class ListScreen extends Component {

static navigationOptions = ({ navigation }) => ({

headerTitle: 'ListScreen',

headerStyle: {

backgroundColor: '#f4511e'

},

headerTitleStyle: {

flex: 1,

textAlign: 'center',

color: '#FFFFFF',

fontSize: 26

},

headerLeft:(

<TouchableOpacity

style={styles.buttonContainer}

onPress={()=>{navigation.goBack();}}

>

<Text style={styles.headerLeftTextStyle}>返回{navigation.getParam('prevScreenTitle','为空时显示这段文字')}</Text>

</TouchableOpacity>

),

headerRight: (

<TouchableOpacity

style={styles.buttonContainer}

onPress={()=>{navigation.navigate('Item', { prevScreenTitle: 'ListScreen' });}}

>

<Text style={styles.headerRightTextStyle}>进入ItemScreen</Text>

</TouchableOpacity>

)

})

render(){

const { navigation } = this.props;

console.log(navigation.getParam('defaultParam'));

return(

<View style={styles.viewStyle}>

<Text>This is ListScreen!</Text>

</View>

);

}

}

ListScreen.propTypes = {

navigation: PropTypes.object

};

const styles = StyleSheet.create({

viewStyle: {

flex: 1,

justifyContent: 'center',

alignItems: 'center'

},

buttonContainer: {

backgroundColor: '#FFFFFF',

justifyContent: 'center',

alignItems: 'center',

padding: 5

},

headerLeftTextStyle: {

color: 'blue'

},

headerRightTextStyle: {

color: 'green'

}

});

export default ListScreen;

导航栏样式效果:

页面跳转及参数传递

路由页面跳转使用navigation.navigate函数,第一个参数为跳转的页面名称,第二个参数为传递的参数:

navigation.navigate('List', {param:'some data'}); 

关于接收参数,无论是在创建时设置的默认入参还是跳转页面时传递的参数,都通过getParam函数来获取,第一个参数为参数名称,第二个参数为当没有参数时,以该参数内容作为入参:

const initData = navigation.getParam('param','当没有获取到参数时显示这段文字')

返回上一个页面使用goBack函数:

navigation.goBack()

导航栏与页面内容的数据交互

页面内容通过navigation.setParams来设置导航栏所需数据:

state = {

day: '星期一'

}

componentDidMount() {

this.props.navigation.setParams({ day: this.state.day});

}

导航栏通过navigation.getParam来获取数据:

const day = navigation.getParam('day'); // 星期一

测试代码:

import React, { Component } from 'react';

import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

import PropTypes from 'prop-types';

class ItemScreen extends Component {

static navigationOptions = ({ navigation }) => ({

headerTitle: 'ItemScreen',

headerStyle: {

backgroundColor: '#f4511e'

},

headerTitleStyle: {

flex: 1,

textAlign: 'center',

color: '#FFFFFF',

fontSize: 26

},

headerLeft:(

<TouchableOpacity

style={styles.buttonContainer}

onPress={()=>{navigation.goBack();}}

>

<Text style={styles.headerLeftTextStyle}>返回{navigation.getParam('prevScreenTitle','为空时显示这段文字')}</Text>

</TouchableOpacity>

),

headerRight: (

<TouchableOpacity

style={styles.buttonContainer}

onPress={navigation.getParam('increaseCount')}

>

<Text style={styles.headerRightTextStyle}>计数器 +1</Text>

</TouchableOpacity>

)

})

constructor(props){

super(props);

this.state = {count:0};

}

componentDidMount() {

this.props.navigation.setParams({ increaseCount: this._increaseCount });

}

_increaseCount = () => {

this.setState({ count: this.state.count + 1 });

};

render(){

const { navigation } = this.props;

return(

<View style={styles.viewContainer}>

<Text>计数器结果:{this.state.count}</Text>

<TouchableOpacity

style={[styles.buttonContainer, styles.modalStyle]}

onPress={()=> navigation.navigate('Modal')}

>

<Text style={styles.modalTextStyle}>进入ModalScreen</Text>

</TouchableOpacity>

</View>

);

}

}

ItemScreen.propTypes = {

navigation: PropTypes.object

};

const styles = StyleSheet.create({

viewContainer:{

flex: 1,

justifyContent: 'center',

alignItems: 'center'

},

buttonContainer: {

backgroundColor: '#FFFFFF',

justifyContent: 'center',

alignItems: 'center',

padding: 5

},

headerLeftTextStyle: {

color: 'blue'

},

headerRightTextStyle: {

color: 'green'

},

modalStyle: {

marginTop: 10,

borderWidth: 1,

padding: 5

},

modalTextStyle: {

color: 'red'

},

});

export default ItemScreen;

数据交互效果:

页面切换动画

可在transitionConfig属性配置,不了解结构可以看开篇处的createStackNavigator函数详解,详解测试代码中已经定义了一种动画效果。这里再贴出一份上下切换的动画作为比较:

// 上下切换路由页

transitionConfig: () => ({

transitionSpec: {

duration: 300,

easing: Easing.out(Easing.poly(4)),

timing: Animated.timing,

},

screenInterpolator: sceneProps => {

const { layout, position, scene } = sceneProps;

const { index } = scene;

const height = layout.initHeight;

//沿Y轴平移

const translateY = position.interpolate({

inputRange: [index - 1, index, index + 1],

outputRange: [height, 0, 0],

});

//透明度

const opacity = position.interpolate({

inputRange: [index - 1, index - 0.99, index],

outputRange: [0, 1, 1],

});

return { opacity, transform: [{ translateY }] };

},

})

效果:

若要自定义切换动画,可以使用先了解一下Animated库。也可以参考 react-native系列(13)动画篇:Animated动画库和LayoutAnimation布局动画详解

(小贴士)react-navigation默认情况下负责为您处理 Android 返回按钮,即设备屏幕外的返回键,如果没有处理或不符合您的期望,可以使用RN官网中的BackHandler函数监听实现。

以上就是StackNavigator的一些实用经验,希望能对你有一定参考价值。

以上是 react-native系列(14)导航篇:页面导航StackNavigator参数及使用详解 的全部内容, 来源链接: utcz.com/z/382497.html

回到顶部