title: 翻译|React-navigation导航系统(2)
date: 2017-03-28 07:48:36
categories: 翻译
tags: React-native
Navigators
Navigators允许你定义你的导航结构.Navigators也可以渲染普通的元素,例如你配置好的header和tab bar.
navigators可以是单纯的React组件.
内建的Navigators
react-navigation
包含下面的几个函数帮助你创建navigators:
-
StackNavigator
-一次渲染一个screen,在screen之间切换.当一个新的screen被打开的时候,他被放在栈顶. -
TabNavigator
-渲染出一个tab bar让用户可以在多个screen之间切换. -
DrawNavigator
-渲染一个抽屉,可以从屏幕左边侧滑出.
使用Navigators渲染screen
navigators实际渲染的就是React组件
了解怎么创建screen,读读一下内容:
- Screen
navigation
props允许screen分发navigation动作,例如操作另外一个screen. - Screen
navigationOptions
定制screen的展示方式(例如:header title,tab label)
在顶层组件上调用导航
万一你想在同一级别的Navigation screen之间使用Navigator,你可以使用react的ref
选项:
const AppNavigator = StackNavigator(SomeAppRouteConfigs);
class App extends React.Component {
someEvent() {
// call navigate for AppNavigator here:
this.navigator && this.navigator.dispatch({ type: 'Navigate', routeName, params });
}
render() {
return (
<AppNavigator ref={nav => { this.navigator = nav; }} />
);
}
}
注意:这个解决办法只能用在顶层navigator上.
Navigation Containers
如果navigators没有props的话,他就会表现为顶层navigators.这个方式提供了一个透明的navigator container,这是顶层导航props的来源.
当渲染其中一个navigators的时候,navigation prop是可选的.如果没有navigation prop,container将会管理自己的导航state.他也可以使用URLs,外部链接以及整合android的back button.
为了使用方便,在幕后内建的navigators有这个能力,因为在幕后他们使用了createNavigationContainer
.通常,navigators需要一个navigation prop来执行一定的功能.
onNavigationStateChange(prevState, newState)
当navigation state由顶层navigator变化管理的时候,这一点非常有用.为了达到这个目的,这个函数在每次调用的时候都会使用导航之前的state和导航之后的新state作为参数.
containerOptions
当一个navigator在顶层被使用的时候,这些选项可以来配置这个navigator.
如果一个navigator配置了containerOptions
,但是也接受了navigation
prop,会抛出错误.因为在这种情况下,navigator有两种选择,它就不知道怎么做了.
-
URIPrefic
-app可以处理的URI前缀.在处理deep link
的时候,可以提取路径,并且传递到router.
StackNavigator
给你的app提供screen之间转变的方法,每个转变到的screen会存放在堆栈的栈顶.
默认情况下,StackNavigator配置有iOS和android的外观和感觉:在iOS下,新的screen从屏幕的右侧滑入,在android下,新的screen从底部淡入.iOS下也可以配置为从屏幕底部滑入.
class MyHomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
}
render() {
return (
<Button
onPress={() => this.props.navigation.navigate('Profile', {name: 'Lucy'})}
title="Go to Lucy's profile"
/>
);
}
}
const ModalStack = StackNavigator({
Home: {
screen: MyHomeScreen,
},
Profile: {
path: 'people/:name',
screen: MyProfileScreen,
},
});
定义API
StackNavigator(Routeconfigs,StackNavigatorConfig)
RouteConfigs
route的配置对象是route name到route config的映射(译者:这才是重点),配置对象告诉navigator什么来代表route.
StackNavigator({
// For each screen that you can navigate to, create a new entry like this:
Profile: {
// `ProfileScreen` is a React component that will be the main content of the screen.
screen: ProfileScreen,
// When `ProfileScreen` is loaded by the StackNavigator, it will be given a `navigation` prop.
// Optional: When deep linking or using react-navigation in a web app, this path is used:
path: 'people/:username',
// The action and route params are extracted from the path.
// Optional: Override the `navigationOptions` for the screen
navigationOptions: {
title: ({state}) => `${state.params.username}'s Profile'`,
},
},
...MyOtherRoutes,
});
StackNavigatorConfig
Router的Options:
-
initialRouteName
-设定默认的堆栈的screen.需要和route config的键之一相同. -
initalRouteParams
-初始化route的参数 -
navigationOptions
-默认需要使用的可选参数 -
path
-覆盖route configs的路径设置
可视化选项:
-
mode
-定义渲染和切换之间的样式:-
card
-使用iOS和android标准的切换方法.默认值 -
modal
-使screen从底部滑动显示.仅仅在iOS下使用,Andorid下没有效果
-
-
headerMode
-定制header渲染的方法-
float
-切换界面的时候,用动画效果在screen的顶部渲染header -
screen
-每一个screen都有一个header附着到头部,切换的时候有淡入和淡出的效果.andorid的基本模式 -
none
-没有header的渲染.
-
cardStyle
-使用这个prop来重写或者扩展单个card的默认styleonTransitionStart
-当card开始切换动画的时候,这个函数被调用onTransitionEnd
-当切换动画完成的时候,这个函数被调用
Screen Navigation Options
通常在screen组件中定义静态的navigationOptions
.例如:
class ProfileScreen extends React.Component {
static navigationOptions = {
title: ({ state }) => `${state.params.name}'s Profile!`,
header: ({ state, setParams }) => ({
// Render a button on the right side of the header
// When pressed switches the screen to edit mode.
right: (
<Button
title={state.params.editing ? 'Done' : 'Edit'}
onPress={() => setParams({editing: state.params.editing ? false : true})}
/>
),
}),
};
...
所有的stackNavigator
的navigationOptions
:
-
title
-scene的标题(字符串) -
header
-header bar的配置对象-
visible
-header可视性的切换.只有当headerMode
是screen
的时候才可以工作 -
title
-header可以使用的字符串或者React组件,默认是scene的title
-
backTitle
-iOS back按钮的title字符串或者null
到disable标签,默认设定到scene的title
. -
right
-显示在header右侧的React组件 -
left
-同上,左侧 -
style
-header的Style对象 -
titleStyle
-title组建的Style对象 -
tintColor
-header的着色
-
-
cardStack
-card stack的配置对象-
gesturesEnabled
-不管你是不是用手势,在iOS上是true,在android里是false.
-
Navigator Props
由StackNavigator(...)
创建的navigator组件接收两个props:
screenProps
-向下传递到子screen,例如:
const SomeStack = StackNavigator({
// config
});
<SomeStack
screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
/>
Examples
看看实例SimpleStack.js和ModalStack.js,可以在本地的NavigationPlaygroundapp中运行.
TabNavigator
通常很容易使用TabRouter来创建有几个tabs的screen.
class MyHomeScreen extends React.Component {
static navigationOptions = {
tabBar: {
label: 'Home',
// Note: By default the icon is only shown on iOS. Search the showIcon option below.
icon: ({ tintColor }) => (
<Image
source={require('./chats-icon.png')}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
},
}
render() {
return (
<Button
onPress={() => this.props.navigation.navigate('Notifications')}
title="Go to notifications"
/>
);
}
}
class MyNotificationsScreen extends React.Component {
static navigationOptions = {
tabBar: {
label: 'Notifications',
icon: ({ tintColor }) => (
<Image
source={require('./notif-icon.png')}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
},
}
render() {
return (
<Button
onPress={() => this.props.navigation.goBack()}
title="Go back home"
/>
);
}
}
const styles = StyleSheet.create({
icon: {
width: 26,
height: 26,
},
});
const MyApp = TabNavigator({
Home: {
screen: MyHomeScreen,
},
Notifications: {
screen: MyNotificationsScreen,
},
}, {
tabBarOptions: {
activeTintColor: '#e91e63',
},
});
定义API
TabNavigator(RouteConfigs,TabNavigator)
RouteConfigs
route的配置对象是route name到route config的映射(译者:这才是重点),配置对象告诉navigator什么来代表route.
TabNavigatorConfig
-
tabBarComponent
-作为tab bar的组件.例如,TabView.TabBarBottom
(ios的默认配置),TabView.TabBarTop
(android的默认配置) -
tabBarPosition
-tab bar的位置,可以是top
和bottom
-
swipeEnabled
-是否在tab之间滑动 -
animationEnabled
-变换tabs的时候是否开启动画效果 -
lazyLoad
-是否在需要的时候才惰性加载tabs,代替预渲染 -
tabBarOption
-配置tab bar,看下面
几个Options可以传递到潜在的的router,修改导航的逻辑 -
initialRouteName
-初始化时加载的tab route -
order
-定义tabs顺序的routeName的数组 -
paths
-提供routeName到path配置的映射,重写routeConfigs里的paths设置 -
backBehavior
-back button是不是应该导致tab切换到初始的tab?入如果是的话,设定initialRoute
,否则就是none
.默认到initialRoute
的行为.
TabBarTop
的tabBarOptions
设置(android默认的tab bar)
-
activeTintColor
-激活tab的标签和icon的颜色 -
inactiveTintColor
-未激活tab的标签和icon的颜色 -
showIcon
-是否在tab中显示icon,默认是false -
showLabel
-是否在tab显示label,默认是true -
upperCaseLabel
-tab的label是否是大写,默认是true -
pressColor
-material涟漪效果的颜色(Android>=5.0) -
pressOpacity
-按下tab的透明度变化(iOS和Android<5.0) -
scrollEnabled
-是否是滑动式tabs. -
tabStyle
-tab的样式配置对象 -
indicatorStyle
-tab指示器的样式对象(tab底部的划线) -
labelStyle
-tab label的样式对象 -
style
-tab bar的样式对象
实例:
tabBarOptions: {
labelStyle: {
fontSize: 12,
},
style: {
backgroundColor: 'blue',
},
}
Screen导航的选项
通常在screen组件中定义静态的navigationOptions
.例如:
class ProfileScreen extends React.Component {
static navigationOptions = {
title: ({ state }) => `${state.params.name}'s Profile!`,
tabBar: ({ state, setParams }) => ({
icon: (
<Image src={require('./my-icon.png')} />
),
}),
};
...
所有TabNavigator
的navigationOption
:
-
title
-scene的title(字符串) -
tabBar
-tab bar的config对象:-
visible
-tab bar的可见性的切换 -
icon
-React组件或者函数给出{focused:boolean,tintColor:string}
,返回一个React组件,显示在tab bar -
label
-显示在tab bar中的tab的名字.如果定义为undefined,scene的title
会被使用.如果要隐藏,看前面部分的tabBarOption.showLabel
.
-
Navigator Props
由TabNavigator(...)
创建的navigator组件接收下面的props:
-
screenProps
-向下传递额外的options给子screen,例如:
const TabNav = TabNavigator({
// config
});
<TabNav
screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
/>
抽屉式导航
用来构建抽屉式导航
class MyHomeScreen extends React.Component {
static navigationOptions = {
drawer: () => ({
label: 'Home',
icon: ({ tintColor }) => (
<Image
source={require('./chats-icon.png')}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
}),
}
render() {
return (
<Button
onPress={() => this.props.navigation.navigate('Notifications')}
title="Go to notifications"
/>
);
}
}
class MyNotificationsScreen extends React.Component {
static navigationOptions = {
drawer: () => ({
label: 'Notifications',
icon: ({ tintColor }) => (
<Image
source={require('./notif-icon.png')}
style={[styles.tabIcon, {tintColor: tintColor}]}
/>
),
}),
}
render() {
return (
<Button
onPress={() => this.props.navigation.goBack()}
title="Go back home"
/>
);
}
}
const styles = StyleSheet.create({
icon: {
width: 24,
height: 24,
},
});
const MyApp = DrawerNavigator({
Home: {
screen: MyHomeScreen,
},
Notifications: {
screen: MyNotificationsScreen,
},
});
打开抽屉或者关闭抽屉,分别导航到DrawerOpen
和Drawerclose
.
this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer
定义API
DrawerNavigator(RouteConfigs, DrawerNavigatorConfig)
RouteConfigs
参看前面的内容
DrawerNavigatonConfig
-
drawerWidth
-抽屉的宽度 -
drawerPosition
-选项是left
和right
.默认是left
. -
contentComponent
-用来渲染抽屉内容的组件,例如,navigation item.接收navigation
prop.默认是DrawerView.Items
.了解更多内容看下面内容. -
contentOptions
-配置drawer的内容,看下面内容
几个选项传递给潜在的router,用来修改navigation的逻辑: -
initialRouteName
-初始化route的routeName -
order
-定义drawer item顺序的routeName数组 -
path
-提供一个routeName到path config的映射,重写掉routeConfigs中的path配置 -
backBehavior
-back按钮一定要返回到初始化的route吗?如果是的话,设置到initialRoute
,否则就用none
.默认到initialRoute
的行为.
提供定制化的contentComponent
可以使用react-navigation
重写默认的组件.
const CustomDrawerContentComponent = (props) => (
<View style={style.container}>
<DrawerView.Items {...props} />
</View>
);
const styles = StyleSheet.create({
container : {
flex : 1,
},
});
DrawerView.Item
的contentOptions
配置
-
activeTintColor
-激活的标签的label和icon的颜色 -
activeBackgroundColor
-激活的标签的背景颜色 -
inactiveTintColor
-未激活的标签的label和icon的颜色 -
inactiveBackgroundColor
-未激活的标签的背景颜色 -
style
-内容部分的样式对象
示例:
contentOptions: {
activeTintColor: '#e91e63',
style: {
marginVertical: 0,
}
}
Screen导航的选项
通常在组件中定义静态的navigationOptions
.
class ProfileScreen extends React.Component {
static navigationOptions = {
title: ({ state }) => `${state.params.name}'s Profile!`,
drawer: {
icon: (
<Image src={require('./my-icon.png')} />
),
},
};
...
所有的DrawerNavigation
navigationOption
配置项
-
title
-scene的标题 -
drawer
-drawer的配置对象-
label
-字符串,React组件或者函数被设定{fcoused:boolean,tinColor:string}
返回一个React组件,显示在drawer的边栏上.当label定义为undefined时,scene的``title被使用. -
icon
-React组件或者函数被设定为{fcoused:boolean,tintColor:string}
返回一个React元素,显示在drawer的边栏上.
-
Navigator 的Props
由DrawerNavigator(...)
创建的navigator组件接受下面的props:
-
screenProps
-向下传递额外的options到子screen,例如:
const DrawerNav = DrawerNavigator({
// config
});
<DrawerNav
screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
/>
Screen Navigation Prop
app中的每个screen都接收navigation prop 包含下面的内容:
-
navigate
-(helper)链接的其他的screens -
state
-screen的当前state和routes -
setParam
-(helper)改变route的参数 -
goBack
-(helper)关闭激活的screen并且返回 -
dispatch
-发送一个action到router
Navigation Actions
所有的Navigation Actions都会返回一个对象,这个对象可以使用navigation.dispatch
方法传递到router.
注意:如果你想dispatch react-navigation,你应该使用这个库提供的action creators.
下面的actions是可以使用的:
-
Navigate
-导航到其他的route -
Reset
-使用新的state代替目前的state -
Back
-返回上一个state -
Set Params
-给定的route设置参数 -
Init
-如果state没有定义,用来初始化第一个state
Navigate
Navigatie action
会使用Navigate action
的结果来更新当前的state.
-
routeName
-字符串-必选项,在app的router里注册的导航目的地的routeName. -
params
-对象-可选项-融合进目的地route的参数 -
actions
-对象-可选项-(高级)-如果screen也是一个navigator,次级action可以在子router中运行.在文档中描述的任何actions都可以作为次级action.
import { NavigationActions } from 'react-navigation'
const navigateAction = NavigationActions.navigate({
routeName: 'Profile',
params: {},
action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
})
this.props.navigation.dispatch(navigateAction)
Reset
Reset
action删掉所有的navigation state并且使用几个actions的结果来代替.
-
index
—数组-必选-navigationstate
中route
数组中激活route的index. -
actions
-数组-必选项-Navigation Actions数组,将会替代navigation state
import { NavigationActions } from 'react-navigation'
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Profile'})
]
})
this.props.navigation.dispatch(resetAction)
怎么使用index
参数
index
参数被用来定制化当前激活的route
例如:使用两个routes Profile
和Settings
给一个基础的stakc navigation设置.为了重置route到经过Settings
的激活screen那一点,但是在堆栈中他又存放在Setting
screen之上,你可以这么做:
import { NavigationActions } from 'react-navigation'
const resetAction = NavigationActions.reset({
index: 1,
actions: [
NavigationActions.navigate({ routeName: 'Profile'}),
NavigationActions.navigate({ routeName: 'Settings'})
]
})
this.props.navigation.dispatch(resetAction)
Back
返回到前一个screen并且关闭当前screen.back
action creator接受一个可选的参数:
-
key
-字符串或者空-可选项-如果设定了,navigation将会从设定的key返回.如果是null,navigation将返回到任何地方.
import { NavigationActions } from 'react-navigation'
const backAction = NavigationActions.back({
key: 'Profile'
})
this.props.navigation.dispatch(backAction)
SetParams
当dispatching setParams的时候
,router将会产出一个新的state,这个state是已经改变了特定route的参数,以key作为身份验证
-
params
-对象-必选参数-融合进已经存在的route参数中的新参数 -
key
-字符串-必选参数-Route的key,应该分配给新的参数
import { NavigationActions } from 'react-navigation'
const setParamsAction = NavigationActions.setParams({
params: { title: 'Hello' },
key: 'screen-123',
})
this.props.navigation.dispatch(setParamsAction)
Screen Navigation Options
每个screen都可以配置几个方面的内容,这些内容影响到在父navigators中怎么得到展示.
定制每一个可选项的两种方法
静态配置方法:每一个navigation 可选项都可以被直接设定:
class MyScreen extends React.Component {
static navigationOptions = {
title: 'Great',
};
...
动态配置方法
要么就采用函数式的方法,接受参数,然后返回可选项的值.
-
navigation
-screen的navigation prop和navigation.state
中screen的route -
childRouter
-如果screen是一个navigator,这个参数就是子代router.
class ProfileScreen extends React.Component {
static navigationOptions = {
title: (navigation, childRouter) => {
return navigation.state.params.name + "'s Profile!";
},
};
...
通用的Navigation Options
navigation的可选项title
在每一个navigator之间是通用的,用来设定每一个screen的标题字符串.
class MyScreen extends React.Component {
static navigationOptions = {
title: 'Great',
};
...
不像其他的navigation的可配置项仅仅由navigator view来使用,title 选项可以被环境变量使用来更新浏览器的标题或者app切换时候的标题.
默认的Navigation选项
在screen中定义navigationOption
非常普遍,但是有时候在navigator中定义navitationOptions
也是非常有用
想象下面的场景:你的TabNavigator
代表app中的一个screen.他在顶层StackNavigator
之内:
StackNavigator:
- route1: A screen
- route2: A TabNavigator
现在route2
是激活的,你可能会隐藏header,隐藏route1
的header非常容易,route2
的header应该也很容易隐藏.这就是默认Navigation Option 要做的.可以在navigationOptions
中设定:
TabNavigator({
profile: ProfileScreen,
...
}, {
navigationOptions: {
header: {
visible: false,
},
},
});
提示:你仍然可以在子代导航screen上定制navigationOptions
.-例如,上面的ProfileScreen
.从screen获得的navigationOptions
会和从navigator来的配置按照键-键的方式融合在一起.无论在什么而时间,navigator和screen定义相同的配置(例如:header
),screen会优先使用.因此,当ProfileScreen
激活的时候,你可以使header再次可见.
扩展默认配置:为了使用screen特定的properties扩展默认配置,而不是重写它,你可以像下面一样配置选项:
class ProfileScreen extends React.Component {
static navigationOptions = {
header: (navigation, defaultHeader) => ({
...defaultHeader,
visible: true,
}),
}
...
}
传递到函数的第二个参数作为在navigator中定义的header
的默认值.
Tab Navigation Options
class TabScreen extends React.Component {
static navigationOptions = {
tabBar: ({ state }) => ({
label: 'Tab Label',
icon: ({ tintColor }) => (
<Image
source={require('./tab-icon.png')}
style={[styles.icon, {tintColor: tintColor}]}
/>
),
visible: true
}),
};
};
-
label
-可以是字符串或者是React组件 -
icon
-函数返回icon组件 -
visible
-true或者false,显示或者隐藏tab bar,默认是true
Custom Navigation
一个navigator是任何包含router的React组件.这里是一个基本navigator,使用router的API去获得激活组件来渲染
class MyNavigator extends React.Component {
static router = MyRouter;
render() {
const { state, dispatch } = this.props.navigation;
const { routes, index } = state;
// Figure out what to render based on the navigation state and the router:
const Component = MyRouter.getComponentForState(state);
// The state of the active child screen can be found at routes[index]
let childNavigation = { dispatch, state: routes[index] };
// If we want, we can also tinker with the dispatch function here, to limit
// or augment our children's actions
// Assuming our children want the convenience of calling .navigate() and so on,
// we should call addNavigationHelpers to augment our navigation prop:
childNavigation = addNavigationHelpers(childNavigation);
return <Component navigation={childNavigation} />;
}
}
Navigation Prop
navigation prop传递给navigator的仅仅包含state
和dispatch
,这是当前的navigator的state,但是还有一个事件频道用来发送action request.
所有的navigators都是受控组件:他们总是显示根据props.navigation.state
来显示,他们要改变state,唯一的办法是发送actions到props.navigation.dispatch
.
Navigators可以通过定制他们的router来改变父navigators的行为.例如,当action应该从router.getStateForAction
返回null来阻止其运行的时候.或者一个navigator可以为了定制URI的操作而改写router.getActionForPathParams
,为了输出相对navigation action以及操作router.getStateForAction
的action.
Navigation State
传递到props.navigation.state
的navigation state有下面的结构:
{
index: 1, // identifies which route in the routes array is active
routes: [
{
// Each route needs a name, which routers will use to associate each route
// with a react component
routeName: 'MyRouteName',
// A unique id for this route, used to keep order in the routes array:
key: 'myroute-123',
// Routes can have any additional data. The included routers have `params`
...customRouteData,
},
...moreRoutes,
]
}
Navigation Dispatchers
navigator可以dispatch navigation actions,例如Go to URI,Go back.
如果action被成功操作了,dispatcher将会返回true,否则就是false
构建定制navigators的API
为了帮助开发者实施定制navigators,React Navigation提供了下面的工具
createNavigator
这个工具使用标准方法把router和navigation view合并在一起.
const MyApp = createNavigator(MyRouter)(MyView);
幕后所做的是:
const MyApp = ({ navigation }) => (
<MyView router={MyRouter} navigation={navigation} />
);
MyApp.router = MyRouter;
addNavigationHelpers
接收一个拥有state
和dispatch
的纯navigator的prop,传递的参数是在screen navigation prop中的各种函数,例如navigation.navigate()
和navigation.goBack()
.这些函数是简单的助手函数帮助创建action并且发送到dispatch
.
createNavigationContainer
如果你想让你的navigator作为顶层组件使用(没有navigation prop传入),你可以使用createNavigationContainer
.当缺少navigtion prop的时候,这个工具使你的navigator看起来像一个顶层的导航组件.它将管理app的state,和app级别的导航特性整合在一起,例如操作进出的链接和android的返回按钮行为.