前言:
ReactNavigation出现很久了,并且在最近发布了V2版本,有一些功能的优化,和api的变化。原来的文档已经不适用了,所以新写一篇用来记录一下细节的东西。本篇内容是参照官方英文文档完成。
安装
//推荐yarn
yarn add react-navigation
# or with npm
# npm install --save react-navigation
使用
createStackNavigator
Creating a stack navigator
createStackNavigator是一个返回React组件的函数。
它需要一个路由配置对象,以及一个选项对象(我们现在省略了这个)。
因为createStackNavigator函数返回一个React组件,我们可以直接从App.js导出它以用作我们App的根组件
/**
* Created by 卓原 on 2018/7/4.
* route.js
*/
import {createStackNavigator} from 'react-navigation';
import HomeScreen from "./page/HomeScreen";
import DetailsScreen from "./page/DetailsScreen";
const RootStack = createStackNavigator({
Home: {
screen: HomeScreen
},
Details: {
screen: DetailsScreen
}
});
export default RootStack;
App.js
export default class App extends React.Component {
//第一种写法
render() {
return <RootStack />;
}
//第二种写法
render() {
return (
<View style={{flex: 1}}>
<RootStack/>
</View>
)
}
}
切换路由 方法:
this.props.navigation.navigate('Details')
将新路由推送到堆栈导航器(如果它尚未在堆栈中),否则它将跳转到该屏幕this.props.navigation.push('Details')
继续推送新路由this.props.navigation.popToTop()
返回到堆栈中的第一个屏幕this.props.navigation.goBack()
返回到上层路由
/**
* Created by 卓原 on 2018/7/4.
* DetailsScreen
*/
import React from 'react';
import {
View,
Text,
Button,
} from 'react-native';
export default class DetailsScreen extends React.Component {
render() {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => this.props.navigation.push('Details')}
/>
<Button
title="Go to Home"
onPress={() => this.props.navigation.navigate('Home')}
/>
<Button
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</View>
);
}
}
以我当前的路由页面举例,我从Home,navigate到Deatils,此时我在Details页面,我执行navigate(‘Details’),不会有任何反应,push(‘Details’)便会跳转到一个新的Details页面,此时,执行goback()那么会回到上一个Details。
将参数传递给下一个路由
通过将params放入一个对象作为navigation.navigate
函数的第二个参数,params传递:this.props.navigation.navigate('RouteName',{/ * params go here * /})
获取前一个路由传递的参数:this.props.navigation.getParam(paramName,defaultValue)
//Home页面
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details', {name: '卓原'})}
/>
//Details页面
const name = navigation.getParam('name', '帅哥');
const age = navigation.getParam('age', 16);
const prevObj = navigation.state.params;
如上代码所示,我跳到Details页面时传递了个对象,名叫卓原的人,接收的时候,我本身并不知道传来的是什么,但我有一个默认的属性,默认属性是一个16岁的帅哥,我接收到了前面传来的名字,于是我的属性变成了16岁的卓原。
还可以使用this.props.navigation.state.params
直接访问params对象。
如果没有提供params,这可能为null,因此通常使用getParam
更容易,因为不必处理这种情况。
配置标题栏
设置标题
屏幕组件可以具有名为navigationOptions的静态属性,该属性是对象或返回包含各种配置选项的对象的函数。
我们用于标题的是title
,如以下示例所示
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
/* render function, etc */
}
默认情况下,createStackNavigator使用平台约定,因此在iOS上标题将居中,而在Android上它将是左对齐的
在标题中使用params
为了在标题中使用params,我们需要使navigationOptions成为一个返回配置对象的函数
export default class DetailsScreen extends React.Component {
static navigationOptions = ({navigation,navigationOptions }) => {
console.log(navigation)
return {
title: navigation.getParam('name', 'A Nested Details Screen'),
};
};
/* render function, etc */
}
使用setParams更新navigationOptions
通常需要从已安装的屏幕组件本身更新活动屏幕的navigationOptions配置。我们可以使用this.props.navigation.setParams
来做到这一点.
<Button
title="Update the title"
onPress={() => this.props.navigation.setParams({name: 'Updated!'})}
/>
此时,我们的标题就从卓原
变成了 Updated!
调整标题样式
自定义标题样式时,有三个关键属性:headerStyle
,headerTintColor
和headerTitleStyle
。
- headerStyle:将应用于title的View的样式对象。如果在其上设置backgroundColor,那将是标题的颜色。
- headerTintColor:后退按钮和标题都使用此属性作为其颜色。
- headerTitleStyle:如果我们要为标题自定义字体Family,font Weight和其他Text style属性,我们可以用它来做
static navigationOptions = {
title: 'Home',
headerStyle: { //标题栏样式
backgroundColor: 'red',
},
headerTintColor: '#fff', //标题文字和按钮颜色
headerTitleStyle: { //标题文字样式
fontWeight: 'bold',
// color:'blue' 如果这里也写了标题文字的颜色,那么会覆盖headerTintColor的颜色,即标题为蓝色
},
};
以上代码对应的标题样式
跨屏幕共享通用navigationOptions
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
/* No more header config here! */
};
/* render function, etc */
}
------------------------------------------分割线------------------------------------------------
const RootStack = createStackNavigator({
Home: {
screen: HomeScreen
},
Details: {
screen: DetailsScreen
}
}, {
/* 主屏幕的标题配置现在在这里 */
navigationOptions: {
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}
});
现在,任何属于RootStack的屏幕的标题栏都将采用这个navigationOptions。
当然,也可以像之前那样,在页面中配置标题样式,那会覆盖共享的navigationOptions。
用自定义组件替换标题
有时候,您需要更多的控制权,而不仅仅是改变标题的文本和样式 - 例如,您可能想渲染图像来代替标题,或者将标题变为按钮。
在这些情况下,您可以完全覆盖用于标题的组件并提供您自己的组件。
import React from 'react';
import {
View,
Text,
Button,
Image
} from 'react-native';
export default class LogoTitle extends React.Component {
render() {
return (
<Image
source={require('../../image/title.png')}
style={{width: 30, height: 30}}
/>
);
}
}
export default class HomeScreen extends React.Component {
static navigationOptions = {
// headerTitle instead of title
headerTitle: <LogoTitle/>,
};
/* render function, etc */
}
这样,标题文字就变成了一张图片。
向标题添加按钮
与标题交互的最常用方法是点击标题左侧或右侧的按钮。
static navigationOptions = {
// headerTitle instead of title
headerTitle: <LogoTitle/>,
headerRight: (
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="blue"
/>
),
};
自定义后退按钮
createStackNavigator为后退按钮提供特定于平台的默认值。
在iOS上,这包括按钮旁边的标签,当标题适合可用空间时显示上一屏幕的标题,否则显示“Back”。
可以使用headerBackTitle
和headerTruncatedBackTitle
更改标签行为。
要自定义后退按钮图像,可以使用headerBackImage
。
tips:
headerBackTitle
,headerTruncatedBackTitle
必须在原始屏幕中定义,而不是在目标屏幕中定义。
export default class DetailsScreen extends React.Component {
static navigationOptions = ({navigation, navigationOptions}) => {
console.log(navigation)
return {
title: navigation.getParam('name', 'A Nested Details Screen'),
headerBackImage: <Image
source={require('../../image/title.png')}
style={{width: 30, height: 30}}
/>
};
};
...
}
createStackNavigator API
API定义
createStackNavigator(RouteConfigs, StackNavigatorConfig);
RouteConfigs
route configs对象是从路由名称到路由配置的映射,它告诉导航器为该路由提供什么。
createStackNavigator({
// 对于您可以导航到的每个屏幕,请创建一个这样的新条目:
Profile: {
// `ProfileScreen` 是一个React组件,它将成为屏幕的主要内容.
screen: ProfileScreen,
// 当StackNavigator加载`ProfileScreen`时,它将被赋予`navigation` prop.
// 可选: 在Web应用程序中深度链接或使用react-navigation时,将使用以下路径:
path:'people /:name',
// 动作和路线参数从路径中提取。
// 可选: 覆盖屏幕的`navigationOptions`
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.name}'s Profile'`,
}),
},
...MyOtherRoutes,
});
StackNavigatorConfig
路由器的选项:
initialRouteName
- 设置堆栈的默认屏幕。必须匹配路径配置中的一个键。
initialRouteParams
- 初始路线的参数
initialRouteKey
- 初始路由的可选标识符
navigationOptions
- 用于屏幕的默认导航选项
paths
- 路径配置中设置的路径的覆盖映射
视觉选项:
mode
- 定义渲染和转换的样式:
- card - 使用标准的iOS和Android屏幕过渡。这是默认值。
- modal - 使屏幕从底部滑入,这是一种常见的iOS模式。仅适用于iOS,对Android没有影响。
headerMode
- 指定标头的呈现方式:
- float - 渲染单个标题,保持在顶部,并在屏幕更改时设置动画。这是iOS上的常见模式。
- screen - 每个屏幕都附有一个标题,标题与屏幕一起淡入和淡出。这是Android上的常见模式。
- none - 不会呈现标题。
headerTransitionPreset
- 指定headerMode: float启用时标头应如何从一个屏幕转换到另一个屏幕。
fade-in-place
- 标题组件交叉淡入淡出而不移动,类似于iOS的Twitter,Instagram和Facebook应用程序。这是默认值。uikit
- iOS的默认行为的近似值。
cardStyle
- 使用此prop可以覆盖或扩展堆栈中单个卡的默认样式。
transitionConfig
- 返回与默认屏幕转换合并的对象的函数(在类型定义中查看TransitionConfig )。提供的函数将传递以下参数:
- transitionProps - 为新屏幕过渡道具。
- prevTransitionProps - 转换旧屏幕的道具。
- isModal - 布尔值,指定屏幕是否为模态。
onTransitionStart
- 卡转换动画即将开始时要调用的函数。
onTransitionEnd
- 卡过渡动画完成后要调用的函数。
navigationOptions 用于导航器内的屏幕
title
可用作后备的字符串headerTitle。此外,将用作tabBarLabel(如果嵌套在TabNavigator中)或drawerLabel(如果嵌套在DrawerNavigator中)的后备。
header
React元素或给定的函数HeaderProps返回React元素,以显示为标题。设置为null隐藏标题。
headerTitle
标题使用的字符串,反应元素或反应组件。默认为场景title。当使用的成分,它接收allowFontScaling,style和children道具。传递标题字符串children。
headerTitleAllowFontScaling
标题标题字体是否应缩放以遵守“文本大小”辅助功能设置。默认为true。
headerBackImage
React Element或Component在标题的后退按钮中显示自定义图像。使用组件时,它在渲染(tintColor,title)时会收到许多道具。默认为带有react-navigation/views/assets/back-icon.png后方图像源的图像组件,后者是平台的默认后退图标图像(iOS上的V形符号和Android上的箭头)。
headerBackTitle
iOS上后退按钮使用的标题字符串,或null禁用标签。默认为上一个场景headerTitle。headerBackTitle必须在原始屏幕中定义,而不是在目标屏幕中定义。例如,当您有转换A到B并且要禁用headerBackTitleon时B:
StackNavigator({
A: {
screen: AScreen,
navigationOptions: () => ({
title: `A`,
headerBackTitle: null
}),
},
B: {
screen: BScreen,
navigationOptions: () => ({
title: `B`,
}),
}
});
headerTruncatedBackTitle
当按钮headerBackTitle不适合屏幕时,后退按钮使用的标题字符串。”Back”默认。headerTruncatedBackTitle必须在原始屏幕中定义,而不是在目标屏幕中定义。例如,如果您有转换A到B并且想要截断标签B:
StackNavigator({
A: {
screen: AScreen,
navigationOptions: () => ({
title: `A`,
headerBackTitle: 'A much too long text for back button from B to A',
headerTruncatedBackTitle: `to A`
}),
},
B: {
screen: BScreen,
navigationOptions: () => ({
title: `B`,
}),
}
});
headerRight
React Element显示在标题的右侧。
headerLeft
React元素或组件显示在标题的左侧。当使用的成分,它接收到一个数道具呈现时(onPress,title,titleStyle和更多-检查Header.js完整的列表)。
headerStyle
标题的样式对象
headerForceInset
允许将forceInset对象传递给标头中使用的内部SafeAreaView。
headerTitleStyle
标题组件的样式对象
headerBackTitleStyle
后标题的样式对象
headerTintColor
标题的色调
headerPressColorAndroid
材质波纹的颜色(Android> = 5.0)
headerTransparent
默认为false。如果true,标题将没有背景,除非您明确地提供headerStyle或headerBackground。
headerBackground
使用它headerTransparent来提供要在标题的背景中呈现的组件。例如,您可以将其用于模糊视图,以创建半透明标题。
gesturesEnabled
是否可以使用手势来关闭此屏幕。在iOS上默认为true,在Android上默认为false。
gestureResponseDistance
用于覆盖从屏幕边缘开始触摸的距离以识别手势的对象。它具有以下属性:
- horizontal- 数字 - 水平方向的距离。默认为25。
- vertical- 数字 - 垂直方向的距离。默认为135。
gestureDirection
用于覆盖关闭手势方向的字符串。default用于正常行为或inverted从右向左滑动。
Navigator Props
创建的导航器组件StackNavigator(…)采用以下属性:
screenProps - 将额外选项传递给子屏幕,例如:
·const SomeStack = createStackNavigator({
// config
});
<SomeStack
screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
/>
举例:
const ModalNavigator =createStackNavigator(
{
Main: { screen: Main },
Login: { screen: Login },
},
{
headerMode: 'none',
mode: 'modal',
navigationOptions: {
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 height = layout.initHeight;
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 }] };
},
}),
}
);