React Native 中文网
React Navigation 官网
简介
一、安装步骤
1、打开终端,cd到工程所在文件夹
2、yarn add react-navigation
3、yarn add react-native-gesture-handler
4、react-native link react-native-gesture-handler
二、关于React Native工程的一些知识点
1、在ReactNative中,所有的类都视为组件。
2、我们在初始化React Native新项目的时候,会有一个App.js文件。我们运行Xcode显示在屏幕上的根视图就是在这个文件中通过export default
导出的那个组件。
3、在3.x的版本中,需要通过createAppContainer
方法将设置好路由的导航器包装为组件。
否则报错如下:
4、组件的导入,在es6+中,通过import导入其他自定义组件
三、官网Demo分析
// In App.js in a new project
import React from "react";
import { View, Text } from "react-native";
import { createStackNavigator, createAppContainer } from "react-navigation";
class HomeScreen extends React.Component {
render() {
return (
Home Screen
);
}
}
const AppNavigator = createStackNavigator({
Home: {
screen: HomeScreen
}
});
export default createAppContainer(AppNavigator);
结合上面的知识点,分析如下
- 在App.js文件中
- 导入react-navigation
- 定义HomeScreen组件
- 定义导航器组件,设置路由
- 将导航器组件包装后导出,此时导航控制器就是应用的根视图控制器
运行结果:
四、注意点
1、在导入navigation组件后通常需要重启终端,否则报错。
2、我们在使用WebStorm
打开初始化工程项目时,都会默认导出名为App的组件
export default class App extends Component {
render() {
return (
);
}
}
与直接导出 stack navigator 相比,对应用程序根部的组件进行更多的控制通常更有用,所以我们导出一个只渲染了 stack navigator 的组件。
const AppNavigator = createStackNavigator({
Home: {
screen: HomeScreen
}
});
const AppContainer = createAppContainer(AppNavigator);
export default class App extends React.Component {
render() {
return ;
}
}
这里需要注意,我们不可以像书写StyleSheet
那样把
const AppNavigator = createStackNavigator({
Home: {
screen: HomeScreen
}
});
写到App组件的下方,这样做报错如下:
3、页面组件就是创建StackNavigator配置路由的组件。只有页面组件才会拥有导航的一些属性。
页面切换
一、跳转新的页面
如果我们使用未在 stack navigator 中定义的路由名称调用this.props.navigation.navigate 方法,则不会发生任何事情。 换句话说,我们只能导航到已经在我们的 stack navigator 上定义的路由; 不能随便导航到任意组件。
二、多次导航到同一路由
class DetailsScreen extends React.Component {
render() {
return (
Details Screen
);
}
}
如果我们使用this.props.navigation.navigate
导航到同一路由是不起作用的。
我们需要使用this.props.navigation.push
来实现
每次调用
push
时, 我们会向导航堆栈中添加新路由。
三、总结
1、我们可以使用this.props.navigation.navigate('RouteName')
跳转到在stack navigator中已经定义的路由名称对应的新页面,但要注意新路由和当前路由不相等。
2、我们可以使用this.props.navigation.navigate('RouteName')
返回堆栈中的现有页面,如果有多个相同页面,则返回到最底层的页面。
生命周期
在React Navigation
中,react的生命周期仍然适用。
只要页面处于加载的状态,react生命周期中的componentDidMount
和componentWillUnmount
方法就不会被调用,这类似于iOS开发中的ViewDidLoad
方法和dealloc
方法,在生命周期中,只会调用一次。那么类比OC,我们如何监听ViewWillAppear
、ViewDidAppear
、ViewWillDisappear
和ViewDidDisappear
的方法呢?
主要有下面两种方式
1、订阅React Navigation事件
2、使用 withNavigationFocus HOC或者
以
假定这样一个场景:导航控制器的根视图控制器是HomeScreen,点击HomeScreen上面的按钮跳转到下一个控制器。那么我们要监听HomeScreen的四个事件。
代码如下:
class HomeScreen extends Component{
render() {
return (
console.log('will focus',payload)}
onDidFocus={payload => console.log('did focus',payload)}
onWillBlur={payload => console.log('will blur',payload)}
onDidBlur={payload => console.log('did blur',payload)}
/>
Home页面
)
}
}
打印如下:
传递参数给路由
一、参数传递
1、使用this.props.navigation.navigate('RouteName', { /* params go here */ })
方法的第二个参数传递给路由
2、推荐传递的参数是 JSON序列化的
this.props.navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
二、获取参数
1、直接使用this.props.navigation.state.params
进行访问,如果没有对应参数,则可能是null。
2、使用his.props.navigation.getParam
进行访问
const { navigation } = this.props;
//第二个参数是设置默认值
const itemId = navigation.getParam('itemId', 'NO-ID');
3、如果你想通过 prop 直接访问 params(例如: this.props.itemId
)而不是this.props.navigation.getParam
,您可以使用社区开发的 react-navigation-props-mapper软件包。
4、官方Demo
class HomeScreen extends React.Component {
render() {
return (
Home Screen
);
}
}
class DetailsScreen extends React.Component {
render() {
/* 2. Get the param, provide a fallback value if not available */
const { navigation } = this.props;
const itemId = navigation.getParam('itemId', 'NO-ID');
const otherParam = navigation.getParam('otherParam', 'some default value');
return (
Details Screen
itemId: {JSON.stringify(itemId)}
otherParam: {JSON.stringify(otherParam)}
);
}
}
配置标题栏
一、设置不含参数的标题栏
1、每个页面组件可以有一个名为navigationOptions
的静态属性,用于设置标题栏的标题使用的是title属性
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
/* render function, etc */
}
二、设置含参数的标题栏
我们将navigationOptions
作为一个函数,react会使用包含{ navigation, navigationOptions, screenProps }这些属性的对象调用它,由于传值只用到navigation,所以代码如下:
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
};
/* render function, etc */
}
对上面提到的三个属性,解释如下:
-
navigation
- 页面的 导航属性 ,在页面中的路由为navigation.state
。 -
screenProps
- 从导航器组件上层传递的 props -
navigationOptions
- 如果未提供新值,将使用的默认或上一个选项(这里说的默认值就是指共享的navigationOptions)
三、更新含参数的标题栏
通常有必要从已加载的页面组件本身更新当前页面的navigationOptions配置。 我们可以使用this.props.navigation.setParams
/* Inside of render() */
this.props.navigation.setParams({otherParam: 'Updated!'})}
/>
四、调整标题样式
定制标题样式时有三个关键属性:headerStyle、headerTintColor和headerTitleStyle。
headerStyle:一个应用于 header 的最外层 View 的 样式对象, 如果你设置 backgroundColor ,他就是header 的颜色。
headerTintColor:返回按钮和标题都使用这个属性作为它们的颜色。 在下面的例子中,我们将 tint color 设置为白色(#fff),所以返回按钮和标题栏标题将变为白色。
headerTitleStyle:如果我们想为标题定制fontFamily,fontWeight和其他Text样式属性,我们可以用它来完成。
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
};
/* render function, etc */
}
五、跨页面共享通用的navigationOptions
如果我们要统一配置标题栏的样式,我们只需把这些代码移动到创建导航器的代码中,放在defaultNavigationOptions
属性下
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
/* No more header config here! */
};
/* render function, etc */
}
/* other code... */
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
/* The header config from HomeScreen is now here */
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
}
);
六、覆盖共享的navigationOptions
如果在页面组件上面也指定了navigationOptions,那么将会覆盖父级的navigationOptions。
七、使用自定义组件替换标题
class LogoTitle extends React.Component {
render() {
return (
);
}
}
class HomeScreen extends React.Component {
static navigationOptions = {
// headerTitle instead of title
headerTitle: ,
};
/* render function, etc */
}
标题栏按钮
1、向标题栏中添加一个按钮
class HomeScreen extends React.Component {
static navigationOptions = {
headerTitle: ,
headerRight: (
alert('This is a button!')}
title="Info"
color="#fff"
/>
),
};
}
在navigationOptions中this绑定的不是 HomeScreen 实例,所以你不能调用setState方法和其上的任何实例方法。
2、标题栏和其所属的页面之间的交互
由于上面提到的,在navigationOptions中不能使用this,所以使用getParam
和setParam
实现
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: ,
headerRight: (
),
};
};
componentDidMount() {
this.props.navigation.setParams({ increaseCount: this._increaseCount });
}
state = {
count: 0,
};
_increaseCount = () => {
this.setState({ count: this.state.count + 1 });
};
/* later in the render function we display the count */
}
下面分析一下这段代码:
1、首先按钮的点击事件我们应该传递一个函数
或者null
。
所以在componentDidMount
方法中将参数赋值为一个函数
此时再次点击按钮的时候就会调用这个函数了。
2、React Navigation
不保证屏幕组件在标题之前安装,此时按钮点击事件相当于null
,不会造成异常。
Tab Navigation
在iOS开发中,最常见的UI框架是Tab中包含若干Navigation。相应的路由配置如下:
import Main from './Component/Main.js';
import Home from './Component/Home.js';
import Find from './Component/Find.js';
import Message from './Component/Message.js';
import Mine from './Component/Mine.js';
//创建navigation
const MainStack = createStackNavigator({
main:{
screen:Main,
}
})
const HomeStack = createStackNavigator({
home:{
screen:Home,
},
})
const FindStack = createStackNavigator({
find:{
screen:Find,
}
})
const MessageStack = createStackNavigator({
home:{
screen:Message,
}
})
const MineStack = createStackNavigator({
home:{
screen:Mine,
}
})
//配置Tab的路由
const TabNav = createBottomTabNavigator({
mainStack:{
screen:MainStack,
},
homeStack:{
screen:HomeStack,
},
findStack:{
screen:FindStack,
},
messageStack:{
screen:MessageStack,
},
mineStack:{
screen:MineStack,
}
})
const AppContainer = createAppContainer(TabNav);
在实际开发中,我们需要自定义Tab上面的样式,类似于createStackNavigator,我们可以用相同的方法配置navigationOptions。
在我们配置样式时,存在一个注意点。当我们同时使用了createStackNavigator
和createBottomTabNavigator
时,在配置样式时:如果我们想设置Navigation
的样式,我们可以在createStackNavigator
或者Navigator
的页面元素中(就是以导航控制器为容器的那些子控制器)设置。如果我们想配置Tab的样式,我们可以在createBottomTabNavigator
或者navigator
(就是以Tab为容器的那些导航控制器)实例中设置。