React Navigation 5.x教程与配置详解

一、简介

React Navigation是React Native是目前最主流的屏幕页面切换的导航方案。React Navigation 5.x版本是目前最新的稳定版本,相对于老版本的配置方式更接近React Router,更好理解。
reactNative0.60.0以上的版本会省去很多配置,建议使用0.6以上版本
npx react-native init demo --version 0.60.0 //版本号自行定义

二、依赖安装

// 安装react-navigation
yarn add @react-navigation/native
// 安装依赖库
yarn add react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view

注意:链接原生库(0.60版本以上的跳过此步骤)
React Native 0.60及更高版本开始,会自动链接,如果你版本是0.60及以上,这一步就可以跳过;而React Native 0.59以及更低版本则需要手动链接,安装react-native link。

   react-native link react-native-reanimated
   react-native link react-native-gesture-handler
   react-native link react-native-screens
   react-native link react-native-safe-area-context

安装navigator库
有三种导航模式可以选,分别是StackNavigator栈导航、TabNavigator标签导航、DrawerNavigator抽屉导航,下面会分别说一下怎么使用。

   //StackNavigator
   npm install @react-navigation/stack
   //TabNavigator
   npm install @react-navigation/bottom-tabs
   //DrawerNavigator
   npm install @react-navigation/drawer

三、StackNavigator导航

使用教程:

1.引入组件

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

2.创建栈导航
createStackNavigator提供APP屏幕之间切换的能力,它是以栈的形式来管理屏幕之间的切换,新切换到的屏幕会放在栈的顶部。

   const Stack = createStackNavigator();

3.将需要进行屏幕切换的组件放入栈导航里

   function App() {
     return (
       <NavigationContainer>
         <Stack.Navigator>
           <Stack.Screen name="Home" component={HomeScreen} />
         </Stack.Navigator>
       </NavigationContainer>
     );
   }

4.完整代码

app/views/LoginScreen.js

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

export default class HomeScreen extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <View>
                <TouchableOpacity  onPress={() => this.props.navigation.navigate('Home')}>
                    <Text >跳转首页</Text>
                </TouchableOpacity>
            </View>
        )
    }
}

app/views/HomeScreen.js

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

export default class HomeScreen extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <View>
        <TouchableOpacity  onPress={() => this.props.navigation.navigate('Login')}>
          <Text >跳转登陆</Text>
        </TouchableOpacity>
      </View>
    )
  }
}

App.js

import 'react-native-gesture-handler';
import React, { Component } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
//引入页面模块
import LoginScreen from './app/views/LoginScreen';
import HomeScreen from './app/views/HomeScreen';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Login" component={LoginScreen} />
        <Stack.Screen name="Home" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

详细参数与配置说明

  • Stack.Navigator的配置选项
    1. initialRouteName
      首次加载名称
    2. screenOptions
      屏幕的默认选项。如下示例。
<Stack.Navigator
initialRouteName="Page1"     //作为初始化页面、不写的话默认第一个screen为初始化页面
screenOptions={{                 //用来定制头部信息、根据自己需要更改
  title: '测试标题',
  headerStyle: {
    backgroundColor: '#ee7530'
  },
  headerTintColor: '#fff',
  headerTitleStyle: {
    fontWeight: 'bold',
    fontSize: 20
  }
}}>
  1. keyboardHandlingEnabled
    如果为false,则导航到新屏幕时,屏幕键盘不会自动关闭。默认为true
  2. mode
    定义渲染和过渡的样式
    card:使用标准的iOS和Android屏幕过渡。这是默认值.
    modal:这有两件事:设置headerMode到screen堆栈,除非指定使屏幕从iOS底部的底部滑入,这是一种常见的iOS模式.
  3. headerMode
    指定标题的呈现方式
    float:渲染停留在顶部的单个标题,并在更改屏幕时进行动画处理。iOS上的常见模式。
    screen:每个屏幕都有一个附加的标题,标题随屏幕一起淡入和淡出。Android上的常见模式。
    none :没有标题。
  • Stack.Screen的配置选项
    options
    可用于配置导航器内的各个屏幕
    title
    头部标题
function StackScreen() {
  return (
    //  静态值
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={HomeScreen}
        options={{ title: 'My home' }}
      />
      // 动态获取
      <Stack.Screen
        name="Profile"
        component={HomeScreen}
        options={({ route }) => ({ title: route.params.name })}
      />
    </Stack.Navigator>
  );
}
/* 在组件中修改使用setOptions */
    <Button
      title="Update the title"
      onPress={() => navigation.setOptions({ title: 'Updated!' })}
    />

header
函数,返回一个React Element,显示为标题。如下示例。

    header: ({ scene, previous, navigation }) => {
          const { options } = scene.descriptor;
          const title =
            options.headerTitle !== undefined
              ? options.headerTitle
              : options.title !== undefined
              ? options.title
              : scene.route.name;
        
          return (
            <MyHeader
              title={title}
              leftButton={
                previous ? <MyBackButton onPress={navigation.goBack} /> : undefined
              }
              style={options.headerStyle}
            />
          );
        };

headerShown
是显示还是隐藏屏幕标题。默认情况下显示标题,除非将headerMode其设置为none。设置为 false隐藏标题。在特定屏幕上隐藏标题时,您可能还需要将headerModeprop 设置为screen。
headerTitle
字符串或返回标头要使用的React元素的函数。默认为 title 选项值.

function LogoTitle() {
  return (
    <Image
      style={{ width: 50, height: 50 }}
      source={require('@expo/snack-static/react-native-logo.png')}
    />
  );
}

function StackScreen() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={HomeScreen}
        options={{ headerTitle: props => <LogoTitle {...props} /> }}
      />
    </Stack.Navigator>
  );
}

headerTitleAlign
对齐标题。可选择left或center。默认为iOS-center和Android-left
headerTitleAllowFontScaling
标头标题字体是否应缩放以符合“文本大小”辅助功能设置。默认为false。
headerBackAllowFontScaling
后退按钮标题字体是否应缩放以符合“文本大小”辅助功能设置。默认为false。
headerBackImage
该函数返回一个React Element以在标题的后退按钮中显示自定义图像。使用函数时,它将tintColor在其参数对象中接收。默认为带有背面图像源的Image组件,它是平台的默认背面图标图像(iOS上为人字形,Android上为箭头)。
headerBackTitle
iOS上的后退按钮使用的标题字符串。默认为上一个场景的headerTitle。
headerBackTitleVisible
为后退按钮标题是否可见提供了一个合理的默认值,但是如果您想覆盖它,则可以使用true或false在此选项中使用
headerTruncatedBackTitle
当headerBackTitle屏幕上不适合显示后退按钮时使用的标题字符串。"Back"默认情况下。
headerRight
该函数返回一个React元素以显示在标题的右侧。

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>
  );
}

headerLeft
返回React元素以显示在标题左侧的函数。使用函数时onPress,在呈现时它会接收许多参数(label,labelStyle和more-检查types.tsx以获取完整列表)。
headerStyle
标头的样式对象。例如,您可以在此处指定自定义背景色。
headerTitleStyle
标题组件的样式对象
headerBackTitleStyle
标题的样式对象
headerLeftContainerStyle
自定义headerLeft组件容器的样式,例如添加填充。
headerRightContainerStyle
自定义headerRight组件容器的样式,例如添加填充。
headerTitleContainerStyle
自定义headerTitle组件容器的样式,例如添加填充。默认情况下,headerTitleContainerStyle是具有绝对位置的风格和偏移量都left和right。这可能导致的空白或之间重叠headerLeft和headerTitle如果定制headerLeft被使用。可以通过在中和中进行调整left和right样式来解决。headerTitleContainerStylemarginHorizontalheaderTitleStyle
headerTintColor
标头的色调颜色
headerPressColorAndroid
材料波纹的颜色(仅适用于Android> = 5.0)
headerTransparent
默认为false。如果为true,则标题将没有背景,除非您明确为其提供背景headerBackground。标头也将浮动在屏幕上,使其与下面的内容重叠。
headerBackground
返回React元素以呈现为标题背景的函数。这对于使用背景(例如图像或渐变)很有用。
例如,可以将其headerTransparent用于渲染模糊视图以创建半透明标题。参考下述示例.

import { BlurView } from 'expo-blur';
<Screen
  name="Home"
  component={HomeScreen}
  options={{
    headerTransparent: true,
    headerBackground: () => (
      <BlurView tint="light" intensity={100} style={StyleSheet.absoluteFill} />
    ),
  }}
/>;

headerStatusBarHeight
在标题顶部添加额外的填充以说明半透明的状态栏。默认情况下,它使用设备安全区域插图中的最大值。传递0或自定义值以禁用默认行为,并自定义高度。
cardShadowEnabled
使用此道具在过渡期间具有可见的阴影。默认为true。
cardOverlayEnabled
使用此道具可以在过渡期间在卡下看到半透明的深色覆盖层。默认为trueAndroid和falseiOS。
cardStyle
堆栈中卡的样式对象。您可以在此处提供自定义背景色,以代替默认背景。您还可以指定{ backgroundColor: ‘transparent’ }使前一个屏幕在下面可见(对于透明模式)。这对于实现模态对话框之类的东西很有用。mode: 'modal’使用透明背景时,还应该在堆栈视图配置中指定,这样以前的屏幕就不会分离并且在下面保持可见。
animationEnabled
屏幕上是否应启用过渡动画。如果将其设置为false,则按下或弹出时屏幕不会动画。默认为true。
animationTypeForReplace
当此屏幕替换另一个屏幕时要使用的动画类型。它采用以下值:
push -将使用推送新屏幕的动画
pop -将使用弹出屏幕的动画
默认为push。
当pop被使用时,pop动画被施加到被替换的画面。
gestureEnabled
是否可以使用手势关闭此屏幕。默认为trueiOS,falseAndroid。
gestureResponseDistance
从屏幕边缘开始覆盖触摸距离的对象,以识别手势。该对象可以包含以下属性:
horizontal- 数字 -水平方向的距离。默认为25。
vertical- 数字 -垂直方向的距离。默认值为135。
gestureVelocityImpact
决定手势速度相关性的数字。默认值为0.3。
gestureDirection
手势的方向。与动画有关
transitionSpec
屏幕过渡的配置对象。与动画有关.请点击此处查看
cardStyleInterpolator
插卡各部分的插补样式。与动画有关请点击此处查看
headerStyleInterpolator
标头各部分的内插样式。与动画有关请点击此处查看
safeAreaInsets
屏幕的安全区域插图。这用于避免使用诸如缺口和状态栏之类的元素。默认情况下,将自动检测设备的安全区域插图。您可以使用此选项覆盖行为。接受包含以下可选属性的对象:
top- 数字 -顶部插图的值,例如包含状态栏和槽口的区域。
right- 数字 -左插图的值。
bottom- 数字 -顶部插图的值,例如底部的区域导航栏。
left。- 数字 -右插图的值。

四、TabNavigator导航

底部导航栏,有的app开发的时候需要用到底部导航栏切换。使用方法跟StackNavigator类似。

1.安装:
npm install @react-navigation/bottom-tabs
2.完整代码
App.js

import 'react-native-gesture-handler';
import React, { Component } from 'react';
import { NavigationContainer } from '@react-navigation/native';
//导入
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
//引入页面模块
import LoginScreen from './app/views/LoginScreen';
import HomeScreen from './app/views/HomeScreen';

const Tab = createBottomTabNavigator();

function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator 
        tabBarOptions={{
          activeTintColor: 'red',
          inactiveTintColor: 'gray',
          tabStyle : {
            backgroundColor: '#ddd',
            paddingBottom: 15,
            borderRightWidth: 1,
            borderRightColor: '#fff'
          },
        }}
      >
        <Tab.Screen name="Home" component={HomeScreen} options={{
          headerStyle: {
            backgroundColor: '#f4511e',
          },
          headerTintColor: '#fff',
          headerTitleStyle: {
            fontWeight: 'bold',
          },
        }} />
        <Tab.Screen name="Login" component={LoginScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

export default App;

详细参数与配置说明

Tab.Navigator的配置

  1. initialRouteName
    导航首次加载时要渲染的路线的名称。

  2. screenOptions
    导航中用于屏幕的默认选项。

  3. backBehavior
    后退按钮处理的行为。

    • initialRoute: 返回初始标签
    • order: 返回上一个标签页(按照标签页中显示的顺序)
    • history: 返回上次访问的标签页
    • none:不处理后退按钮
  4. lazy
    默认为true。如果为false,则所有选项卡都将立即呈现。如果为true,则仅在首次使选项卡处于活动状态时才显示它们。注意:选项卡不会在后续访问时重新呈现。

  5. tabBar
    返回React元素以显示为选项卡栏的函数

  6. tabBarOptions
    包含选项卡栏组件的道具的对象。它可以包含以下属性:

    • activeTintColor -活动标签的标签和图标颜色。
    • activeBackgroundColor -活动标签的背景颜色。
    • inactiveTintColor -非活动标签的标签和图标颜色。
    • inactiveBackgroundColor -非活动标签的背景颜色。
    • showLabel -是否显示标签标签,默认为true。
    • showIcon -是否显示标签图标,默认为true。
    • style -标签栏的样式对象。
    • labelStyle -标签标签的样式对象。
    • labelPosition-在何处显示与标签图标相关的标签标签。可用值为beside-icon和below-icon。默认为beside-icon。
    • tabStyle -标签的样式对象。
    • allowFontScaling -标签字体是否应缩放以符合“文本大小”辅助功能设置,默认为true。
    • adaptive-标签图标和标签对齐方式是否应根据屏幕尺寸而改变?true对于iOS 11 false,默认值为。如果,标签图标和标签始终垂直对齐。当时true,标签图标和标签在平板电脑上水平对齐。
    • safeAreaInset-覆盖forceInset道具。默认为{ bottom: ‘always’, top: ‘never’ }。可用的键top | bottom | left | right随值一起提供’always’ | ‘never’。
    • keyboardHidesTabBar-默认为false。如果true在键盘打开时隐藏标签栏。

options 可用于配置导航内的各个屏幕。支持的选项有:

  1. title
    通用标题可以用作备用headerTitle和tabBarLabel。
  2. tabBarVisible
    true或false显示或隐藏标签栏(如果未设置),则默认为true。
  3. tabBarIcon
    给定的函数{ focused: boolean, color: string, size: number }返回一个React.Node,以显示在选项卡栏中。
  4. tabBarLabel
    显示在选项卡栏中的选项卡的标题字符串或给定的函数将{ focused: boolean, color: string }返回React.Node,以显示在选项卡栏中。未定义时,使用场景title。
  5. tabBarButton
    该函数返回一个React元素以呈现为选项卡按钮。它包装图标和标签并实现onPress。TouchableWithoutFeedback默认情况下渲染。tabBarButton: props => <TouchableOpacity {…props} />会TouchableOpacity改为使用。
  6. tabBarAccessibilityLabel
    选项卡按钮的辅助功能标签。当用户点击选项卡时,屏幕阅读器会读取该内容。如果您没有标签的标签,建议您进行设置。
  7. tabBarTestID
    在测试中找到此选项卡按钮的ID。
  8. unmountOnBlur
    离开该屏幕时是否应卸载该屏幕。卸载屏幕将重置屏幕中的任何本地状态以及屏幕中嵌套导航器的状态。默认为false。

五、DrawerNavigator导航

1.安装:

npm install @react-navigation/drawer

2.完整代码

App.js

import 'react-native-gesture-handler';
import React, { Component } from 'react';
import { NavigationContainer } from '@react-navigation/native';
//导入
import { createDrawerNavigator } from '@react-navigation/drawer';
//引入页面模块
import LoginScreen from './app/views/LoginScreen';
import HomeScreen from './app/views/HomeScreen';

const Drawer = createDrawerNavigator();

function App() {
  return (
    <NavigationContainer
      drawerStyle={{
        backgroundColor: '#c6cbef',
        width: 200,
      }}
    >
      <Drawer.Navigator initialRouteName='Home'>
        <Drawer.Screen name='Home' component={HomeScreen} />
        <Drawer.Screen name='Login' component={LoginScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

export default App;

六、组合使用

原生思维是TabNavigator中嵌套StackNavigator,但是这里建议StackNavigator中嵌套TabNavigator。因为可以避免控制TabNavigator的tabbar显示和隐藏问题。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343