React-Native 0.63踩坑之旅--导航react navigation@5.x的使用

2,534 阅读8分钟

目录

前言

环境搭建以及基础组件的使用后,下一步为了能组织成规模的app,导航navigation是必然的,就像前端工程离不开路由router一样。根据资料的学习,了解到react-native有过很多版本的navigation组件,其中包括如下:

  • NavigationIOS:只针对iOS平台开发,它是基于 UINavigationController 封装的,所以看起来很像
  • Navigator : 使⽤JS来实现,将逐步被替代,⽬前仍然可⽤
  • NavigationExperimental: 最早的导航组件,⽬前已经完全弃⽤
  • react-navigation : 目前最流行的导航组件,兼容ios和安卓,也是本篇文章重点介绍的组件

react-navigation的安装

react-navigation的官网

在你的 React Native 项⽬中安装 react-navigation 这个包

# yarn 安装
yarn add @react-navigation/native

# npm 安装
npm install @react-navigation/native -S

然后,安装 react-naviation的相关依赖


# 使用yarn 安装
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

# 使用npm 安装
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view -S

从React Native 0.60及更高版本开始,链接是自动的。 因此,您无需运行react-native链接。


# iOS操作
cd ios
pod install

要完成react-native-gesture-handler的安装,请在条目文件(例如index.js或App.js)的顶部(确保它位于顶部,并且没有其他内容)之前添加以下内容:

import 'react-native-gesture-handler';

例如:

import 'react-native-gesture-handler';
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';

export default function App() {
  return (
    <NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
  );
}

导航器介绍

导航器也可以看成是⼀个普通的React组件,你可以通过导航器来定义你的APP中的导航结构。导航器 还可以渲染通⽤元素,例如可以配置的标题栏和选项卡栏。 在react-navigation中有以下类型的导航器:

  • stacktackNavigator:类似普通的Navigator,导航上⽅导航栏
  • createBottomTabNavigator:底部tab导航
  • createMaterialTopTabNavigator:屏幕顶部的Material设计主题标签栏
  • createDrawerNavigator:抽屉效果,侧边滑出
  • createSwitchNavigator:SwitchNavigator的⽤途是⼀次只显示⼀个⻚⾯,常⽤于welcome⻚⾯或者登陆⻚⾯,这种⻚⾯没有回退操作。

你可以通过以上⼏种导航器来创建你的APP,可以是其中⼀个也可以多个组合,这个可以根据具体的应 ⽤场景并结合每⼀个导航器的特性进⾏选择。

NavigationContainer --各种Navigator的容器

这是一个用来装载各个Navigator的容器,整个工程有且只有一个。 如下:

<NavigationContainer onStateChange={()=>this.stateChange()}>
    <Stack.Navigator>
        <Stack.Screen name="Home" component={Home} options={{ title: '首页' }} />
        <Stack.Screen name="My" component={My} options={{
            title:"我的"
        }}/>
    </Stack.Navigator>
</NavigationContainer>

这个组件的常用的props有

  • theme 设置的主题
  • onStateChange 导航发生变化时的事件监听
  • onReady 导航组件准备好时的事件监听

stacktackNavigator 用的最多的导航

stacktackNavigator是最普通也是使用最为广泛的导航,提供APP屏幕之间切换的能⼒,它是以栈的形式还管理屏幕之间的切换,新切换到的屏幕会放在栈的顶部。

stacktackNavigator 被配置为具有熟悉的iOS和Android外观 & 感觉:新屏幕从iOS右侧滑⼊,从Android底部淡⼊。 在iOS上,stack navigator 也可以配置为屏幕从底部滑⼊的模式样式。

安装stackNavigator

使用npm或者yarn都可以轻松安装

npm install @react-navigation/stack

创建stackNavigator

创建stackNavigation很简单,调用@react-navigation/stack中的createStackNavigator方法创建一个Stack组件,并且需要NavigationContainer组件进行包裹才可以使用。如下: 其中Home和My是不同的页面组件。构建的方式和react-router很类似。

import React, { Component } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

import Home from './pages/home/';
import My from "./pages/my"

const Stack = createStackNavigator();

export default class AppStackContainer extends Component {
    render() {
        return (
            <NavigationContainer>
                <Stack.Navigator>
                    <Stack.Screen name="Home" component={Home} />
                    <Stack.Screen name="My" component={My} />
                </Stack.Navigator>
            </NavigationContainer>
        );
    }
}

页面之间如何跳转

上述例子中讲到了如何配置stackNavigator导航。页面配置完之后,让他们之间相互跳转才是重点。那么stackNavigator给我们提供了navigate、push、goback、popToTop等方法来完成页面跳转。上面例子中的Home页面代码如下:

import React, { Component } from 'react'
import { Text, Button, View, StyleSheet } from 'react-native'

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
});

export default class index extends Component {
    goMyPage(){
        const { navigation } = this.props;
        navigation.navigate('My');
    }

    render() {
        return (
            <View style={styles.container}>
                <Text> Home </Text>
                <Button
                    title="去My page"
                    onPress={() => this.goMyPage()}
                />
            </View>
        )
    }
}

由此可见,页面有一个button,其中点击事件中从props中获取到了navigation对象,这个对象就是NavigationContainer组件注册进来的属性。这也是为什么要用NavigationContainer进行包裹的原因。通过调用navigation对象navigate方法进行跳转,这个方法的第一个参数就是对应的导航Name属性。

navigate

标准的路由跳转方法,可以通过此方法进行随意的页面跳转,但是有一个原则,就是不能重复压栈。比如从Home跳转到了My,如果My页面还有一个按钮再次执行navigation.navigate('My');是不会再次跳转到一个新的My页面。

push

navigation.push('My')和navigation.navigate('My')在功能上有所类似,都是跳转到一个新页面,唯一不同的是,可以使用它进行重复的打开同一个页面。例如在My页面代码如下:

import React, { Component } from 'react'
import { Text, View, Button, StyleSheet } from 'react-native'

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
});

export default class index extends Component {
    render() {
        return (
            <View style={styles.container}>
                <Text> My </Text>
                <Button
                    title="Go to My... again"
                    onPress={() => this.props.navigation.push('My')}
                />
                <Button title="goback" onPress={()=> this.props.navigation.goBack()}></Button>
            </View>
        )
    }
}

上述代码中的Go to My...again的按钮就可以重复的进入My页面。

goback(返回上一个页面)

使用navigation.goBack()就可以返回上一次进来的页面

popToTop(返回最前面的页面)

navigation.popToTop()就可以返回默认首页

页面之间如何传递参数

在常规的开发中,页面之间传递参数是最常见的操作,那么stackNaviator如何在页面之间传递参数呢?其实只需要两步就可以完整

  • 在页面使用使用navigation.navigate('RouteName', { /* params go here */ })进行传递参数的设置。例如:
navigation.navigate('My', {
    itemId: 86,
    otherParam: 'anything you want here',
});
  • 在接收页面的某个时机(mounted事件或者rander函数中)使用route进行接收,例如:
const { route } = this.props;//route也是被注册进来的参数如果这个参数params就可以获取传进来的参数
const { itemId , otherParam} = route.params;
console.log(itemId,otherParam)

设置Header的属性

stackNavigator最大的特点就是有一个header在顶部,那么如何设置它的属性呢?比如背景颜色、字体颜色、标题、以及右侧如何放置按钮等等。

设置标题

静态配置:

function StackScreen() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={HomeScreen}
        options={{ title: 'My home' }}
      />
    </Stack.Navigator>
  );
}

其他属性:

  • title: string, 标题文字
  • headerTitleAlign: 标题对齐方式,支持 left (Android 默认) / center (iOS 默认)
  • headerTitleAllowFontScaling: 标题文字是否随系统文字大小缩放
  • headerTintColor: 标题颜色
  • headerTitleStyle: 自定义标题文字样式
  • headerTitleContainerStyle: 自定义标题文字所在 View 容器的样式
  • headerTitle: 标题,可直接设置文字,优先级高于 title;也可以设置为函数,返回一个组件,函数参数为 {allowFontScaling, style, children},这三个参数是由上面属性结合而来。

左侧按钮配置

  • headerBackImage: 返回键,设置为一个函数,返回“返回键”组件,函数参数为 {tintColor:"标题颜色"}
  • headerBackTitle: string 返回键右侧的返回文字
  • headerTruncatedBackTitle: 返回文字过长,标题栏无法显示时的替代返回文字,默认: "Back"
  • headerBackAllowFontScaling: 返回文字是否随系统文字大小缩放
  • headerBackTitleStyle: 自定义返回文字样式
  • headerBackTitleVisible: 是否显示返回文字,Android 默认 false,iOS 默认 true
  • headerPressColorAndroid: Android 5 以上,点击返回按钮的水波纹颜色
  • headerLeftContainerStyle: 自定义返回键和返回文字所在容器的样式
  • headerLeft: 自定义 HeaderBackButton 左侧组件,指定为函数 或 RN组件,props 会传递上面的返回键和返回文字相关的设置

添加右侧按钮

  • headerRight: 自定义标题栏右侧组件
  • headerRightContainerStyle: 自定义右侧组件所在容器的样式

让我们在标题的右侧添加一个按钮(这是整个屏幕上最难触摸的位置之一,具体取决于手指和手机的大小,也是放置按钮的常规位置)。 例如:

function StackScreen() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={HomeScreen}
        options={{
          headerTitle: props => <LogoTitle {...props} />,
          headerRight: () => (
            <Button
              onPress={() => alert('This is a button!')}
              title="Info"
              color="#fff"
            />
          ),
        }}
      />
    </Stack.Navigator>
  );
}

标题栏整体属性

  • headerStatusBarHeight: 设置 statusBar 高度,Header 组件会 paddingTop 这个值以保证在刘海屏机型也可以正常使用,默认会由系统自动获取。
  • headerStyle: 自定义标题栏样式
  • headerTransparent: 标题栏是否透明,与在 headerStyle 直接设置 backgroundColor 的不同在于:这里设置透明,会使页面的 marginTop 为 0,此时需要定义 headerBackground 组件来遮挡。
  • headerBackground: 标题栏背景组件,配合 headerTransparent 使用的,可以用来实现毛玻璃 Header 效果。
  • safeAreaInsets: Header安全区域设置(针对刘海屏机型),默认情况下会自动设置,但也可以使用 {left, right, top, bottom} 手动设置,自定义设置注意考虑横竖屏的情况。
  • headerShown: 是否显示标题栏
  • header: 自定义标题栏组件,定义为函数,返回一个 RN 组件;设置该属性,即不使用默认 Header 了,以上属性失效。

动态更新 使用setOptions更新options

上述的所有属性都可以通过下面方法进行更新

<Button
  title="Update the title"
  onPress={() => this.props.navigation.setOptions({ title: 'Updated!' })}
/>

设置共享样式

通常希望在许多屏幕上以类似方式配置标题。 例如,您的公司品牌颜色可能是红色,因此您希望标题背景颜色为红色,而色调颜色为白色。 方便地,这些是我们在运行示例中使用的颜色,并且您会注意到,当导航到DetailsScreen时,颜色会恢复为默认值。 如果必须将选项标头样式属性从HomeScreen复制到DetailsScreen,并且对于我们在应用程序中使用的每个单个屏幕组件,这都不可怕吗? 幸运的是,我们没有。 相反,我们可以将配置上移到prop screenOptions下的堆栈导航器中。

例如:

function StackScreen() {
  return (
    <Stack.Navigator
      screenOptions={{
        headerStyle: {
          backgroundColor: '#f4511e',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
          fontWeight: 'bold',
        },
      }}
    >
      <Stack.Screen
        name="Home"
        component={HomeScreen}
        options={{ title: 'My home' }}
      />
    </Stack.Navigator>
  );
}

Tab navigation 底部tab导航

安装

npm install @react-navigation/bottom-tabs

DrawerNavigator 抽屉导航