React Native 导航

摘要:在本教程中,您将学习如何使用 React Navigation 库在 React Native 应用程序中的不同屏幕之间进行导航。

React Navigation 简介

要管理和在 React Native 应用程序中的不同屏幕之间导航,您可以使用 React Navigation 库。

React Navigation 库具有以下主要功能

  • 堆栈导航像堆栈一样管理屏幕,允许您在屏幕之间向前和向后导航。
  • 底部标签导航在屏幕底部显示一个栏。该栏包括带有图标和标签的项目。当您触摸每个标签栏项目时,标签导航将在屏幕之间进行导航。
  • 抽屉导航显示一个侧边栏(或抽屉菜单),您可以滑动和切换它以显示菜单项。

在 React Native 应用程序中,您可以结合使用不同的导航来创建灵活的导航选项。在本教程中,我们将重点介绍构建堆栈导航。

使用 React Navigation 创建 React Native 应用程序

在本节中,您将探索如何在应用程序中设置和使用堆栈导航。

要求

在开始之前,请确保您拥有以下内容

  • react-native >= 0.63.0
  • expo >= 41(如果您使用 Expo Go)

设置新项目

首先,打开您的终端并执行以下命令以创建一个新的 React Native 应用程序

npx create-expo-app nav --template blank

此命令创建 nav 目录并初始化 React Native 应用程序。完成此操作需要一些时间。

其次,导航到项目目录 nav

cd nav

第三,执行以下命令以安装 React Navigation 库

npm install @react-navigation/native @react-navigation/native-stackCode language: CSS (css)

React Navigation 的基本概念

导航器

导航器是一个组件,它允许您管理导航状态和屏幕。React Navigation 包括以下导航器

  • StackNavigator – 用于管理堆栈导航。
  • TabNavigator – 用于管理底部标签导航。
  • DrawerNavigator – 用于创建抽屉。

屏幕

屏幕是一个 React Native 组件,它代表导航器中的一个屏幕。导航器将每个屏幕与一个路由关联起来。

路由

路由是一个对象,它定义了屏幕的路径和参数。

导航道具

navigation 道具在堆栈导航中的每个屏幕组件中都可用。它允许您访问导航方法,如 navigategoBackpushpop 等。

参数

参数是您从一个屏幕传递到另一个屏幕的参数。

例如,您可以从首页传递包含 id 和 name 的对象到个人资料页面。在个人资料页面,您可以读取参数以进行进一步处理。

创建原生堆栈导航器

步骤 1. 在项目目录中创建一个名为 screens 的新目录来存储屏幕。每个屏幕都是一个 React Native 组件。

步骤 2. 在 screens 目录中创建一个 Home 屏幕

import { SafeAreaView, StyleSheet, Text, View } from 'react-native';

const Home = () => {
    return (
        <SafeAreaView style={styles.container}>
            <View style={styles.screen}>
                <Text>Home Screen</Text>
            </View>
        </SafeAreaView>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    screen: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    }
});

export default Home;Code language: JavaScript (javascript)

步骤 3. 在 screens 目录中创建一个 Profile 屏幕

import { SafeAreaView, StyleSheet, Text, View } from 'react-native';

const Profile = () => {
    return (
        <SafeAreaView style={styles.container}>
            <View style={styles.screen}>
                <Text>Profile Screen</Text>
            </View>
        </SafeAreaView>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    screen: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    }
});

export default Profile;Code language: JavaScript (javascript)

步骤 4. 在 screens 目录中创建一个 index.js,导入 HomeProfile 屏幕,并立即导出它们

import Home from './Home.jsx';
import Profile from './Profile.jsx';

export { Home, Profile }Code language: JavaScript (javascript)

通过这样做,您可以使用单个导入从 screens 目录导入所有屏幕

import { Home, Profile} from './screens/index';Code language: JavaScript (javascript)

而且您不必像这样单独导入屏幕

import Home from './screens/Home';
import Profile from './screens/Profile';Code language: JavaScript (javascript)

步骤 5. 将 HomeProfile 屏幕导入 App.js 文件并将 Home 屏幕作为主要组件放置

import { Home, Profile } from './screens/index';

export default function App() {
  return (
    <Home />
  );
}Code language: JavaScript (javascript)

步骤 6. 打开终端并运行应用程序

npm start

步骤 7. 修改 App.js 以创建一个原生堆栈导航器

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Home, Profile } from './screens/index';

const Stack = createNativeStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={Home} />
        <Stack.Screen name="Profile" component={Profile} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}Code language: JavaScript (javascript)

它是如何工作的。

首先,从 React Navigation 库导入 NavigationContainercreateNativeStackNavigator

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';Code language: JavaScript (javascript)

其次,通过调用 createNativeStackNavigator 函数来创建一个堆栈导航器

const Stack = createNativeStackNavigator();Code language: JavaScript (javascript)

注意,变量名不必是 Stack。

createNativeStackNavigator() 函数返回一个对象 (Stack),它有两个属性,两者都是用于配置导航器的 React 组件

  • 屏幕
  • 导航器

第三,使用 NavigationContainer 组件作为应用程序的根组件

<NavigationContainer>
   <Stack.Navigator initialRouteName="Home">
     <Stack.Screen name="Home" component={Home} />
     <Stack.Screen name="Profile" component={Profile} />
    </Stack.Navigator>
</NavigationContainer>
Code language: HTML, XML (xml)

Screen 组件包含 namecomponent 道具

  • name 道具指定用于导航的路由名称。
  • component 道具定义要渲染的 React Native 组件或屏幕。

堆栈导航器有两个路由 HomeProfile。初始路由是显示 Home 屏幕的 Home 路由。

如果您将 initialRouteName 更改为 Profile,您将看到 Profile 屏幕显示而不是 Home 屏幕。

在屏幕之间移动

步骤 1. 修改 Home 屏幕以包含一个按钮以导航到 Profile 屏幕

import { SafeAreaView, StyleSheet, Text, View, Pressable } from 'react-native';
import React from 'react';

const Home = ({ navigation }) => {
    const handlePress = () => {
        navigation.navigate('Profile');
    }
    return (
        <SafeAreaView style={styles.container}>
            <View style={styles.screen}>
                <Text>Home Screen</Text>
                <Pressable onPress={handlePress} style={styles.button}>
                    <Text style={styles.buttonText}>Go to the Profile screen</Text>
                </Pressable>
            </View>
        </SafeAreaView>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    screen: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    button: {
        backgroundColor: '#FFD966',
        paddingHorizontal: 20,
        paddingVertical: 10,
        borderRadius: 99,
        alignItems: 'center',
        marginVertical: 10,

    },
    buttonText: {
        color: '#4B4942',
        fontSize: 16,
    },
});

export default Home;Code language: JavaScript (javascript)

当您按下按钮时,您将导航到 Profile 屏幕。如果您点击标题上的后退按钮,您将返回到 Home 屏幕。

它是如何工作的。

首先,将 navigation 道具包含在 Home 组件中。请注意,包含在导航堆栈中的所有屏幕都将自动具有 navigation 道具

const Home = ({ navigation }) => {Code language: JavaScript (javascript)

其次,通过使用 Profile 路由名称调用 navigation 对象的 navigate() 方法,在 handlePress 回调中导航到 Profile 屏幕

const handlePress = () => {
   navigation.navigate('Profile');
}Code language: JavaScript (javascript)

如果您想从 Profile 屏幕以编程方式返回到 Home 屏幕,您可以使用 navigation 对象的 goBack() 方法。

步骤 2. 修改 Profile 屏幕以包含一个按钮,当按下时,返回到 Home 屏幕

import { SafeAreaView, StyleSheet, Text, View, Pressable } from 'react-native';

const Profile = ({ navigation }) => {
    const handlePress = () => {
        navigation.goBack();
    }

    return (
        <SafeAreaView style={styles.container}>
            <View style={styles.screen}>
                <Text>Profile Screen</Text>

                <Pressable onPress={handlePress} style={styles.button}>
                    <Text style={styles.buttonText}>Go back to the Home screen</Text>
                </Pressable>
            </View>
        </SafeAreaView>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    screen: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    button: {
        backgroundColor: '#FFD966',
        paddingHorizontal: 20,
        paddingVertical: 10,
        borderRadius: 99,
        alignItems: 'center',
        marginVertical: 10,

    },
    buttonText: {
        color: '#4B4942',
        fontSize: 16,
    },
});

export default Profile;Code language: JavaScript (javascript)

在屏幕之间传递数据

要传递数据在屏幕之间,请按照以下步骤操作

首先,将对象作为 navigation.navigate() 方法的第二个参数传递

navigation.navigate(routeName, {
   id: 1, 
   name: 'John Doe'
});Code language: CSS (css)

其次,使用 route.params 对象在另一个屏幕上读取数据

const data = route.params;Code language: JavaScript (javascript)

navigation 道具一样,route 是组件的道具,例如

const Profile = ({ navigation, route }) => {
}Code language: JavaScript (javascript)

您也可以解构 route.params 对象中的数据

const {id, message} = route.params;Code language: JavaScript (javascript)

以下示例展示了如何将数据从 Home 传递到 Profile 屏幕

步骤 1. 修改 handlePress 函数以将对象作为 navigation.navigate() 方法的第二个参数传递

const handlePress = () => {
    navigation.navigate('Profile', {
          id: 1,
          name: 'John Doe',
    });
}Code language: JavaScript (javascript)

步骤 2. 修改 Profile 屏幕以读取从 Home 屏幕传递的数据

import { SafeAreaView, StyleSheet, Text, View, Pressable } from 'react-native';

const Profile = ({ navigation, route }) => {
    const { id, name } = route.params;
    const handlePress = () => {
        navigation.goBack();
    }

    return (
        <SafeAreaView style={styles.container}>
            <View style={styles.screen}>
                <Text>id: {id}</Text>
                <Text>name: {name}</Text>
                <Pressable onPress={handlePress} style={styles.button}>
                    <Text style={styles.buttonText}>Go back to the Home screen</Text>
                </Pressable>
            </View>
        </SafeAreaView>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    screen: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
    },
    button: {
        backgroundColor: '#FFD966',
        paddingHorizontal: 20,
        paddingVertical: 10,
        borderRadius: 99,
        alignItems: 'center',
        marginVertical: 10,

    },
    buttonText: {
        color: '#4B4942',
        fontSize: 16,
    },
});

export default Profile;Code language: JavaScript (javascript)

它是如何工作的。

首先,从 route.params 对象中解构 idname

const { id, name } = route.params;Code language: JavaScript (javascript)

其次,在屏幕上显示 id 和 name

<Text>id: {id}</Text>
<Text>name: {name}</Text>Code language: JavaScript (javascript)

自定义屏幕标题

更改标题

Screen 组件有一个 options 道具,它接受一个对象或一个函数,该函数返回一个用于配置屏幕标题的对象。

例如,您可以将 Home 屏幕的 Home 标题更改为 Welcome,如下所示

<Stack.Screen
  name="Home"
  component={Home}
  options={{ title: 'Welcome' }}
/>Code language: JavaScript (javascript)

在此示例中,我们将 Home 屏幕的 options 道具设置为一个对象,该对象包含 title 'Welcome'Home 屏幕在 Android 上应该看起来像下图

React Native Navigation - Changing header title

要使用 params 作为标题,您需要将函数传递给 options 道具并通过 route 访问 params

例如,以下说明了如何使用 name 参数作为 Profile 屏幕的标题

<Stack.Screen
  name="Profile"
  component={Profile}
  options={({ route }) => ({ title: route.params.name })}
/>Code language: JavaScript (javascript)

在此示例中,我们将一个箭头函数传递给 options 道具。该函数访问 route 道具并将标题设置为 name 参数

React Native Navigation - Changing header title to params

此外,您还可以通过调用 navigation 对象的 setOptions 方法来更新活动屏幕的 options

navigation.setOptions({title: 'John Doe Profile'})Code language: JavaScript (javascript)

自定义标题样式

除了动态更改标题之外,您还可以通过以下属性自定义屏幕标题的样式

  • headerStyle 属性定义应用于包装标题的 View 的样式。例如,您可以为标题设置背景颜色。
  • headerTintColor 属性定义后退按钮和标题的颜色。
  • headerTitleStyle 属性定义标题的样式,如 fontFamilyfontWeight 和其他Text 样式。

以下示例更改了 Home 屏幕的标题样式

<Stack.Screen
  name="Home"
  component={Home}
  options={{
    title: 'Welcome',
    headerStyle: {
      backgroundColor: '#FFD966',
    },
    headerTintColor: '#4B4942',
    headerTitleStyle: {
      fontWeight: 'bold',
    },
  }}
/>Code language: JavaScript (javascript)
React Native Navigation - Changing header style

要共享跨屏幕的相同标题样式,您可以将配置移到 screenOptions 道具下的原生堆栈导航器

<Stack.Navigator
  initialRouteName="Home"
  screenOptions={{
    headerStyle: {
      backgroundColor: '#FFD966',
    },
    headerTintColor: '#4B4942',
    headerTitleStyle: {
      fontWeight: 'bold',
    }
  }}>
{/* ... */}
</Stack.Navigator>    Code language: JavaScript (javascript)

现在,所有屏幕(包括 Home 和 Profile 屏幕)共享相同的标题样式

用自定义组件替换标题

React Navigation 允许您用自定义组件替换标题。例如。

步骤 1. 创建一个名为 components 的新目录来存储 React 组件。

步骤 2. 在 components 目录中创建一个名为 ProfileHeaderTitle 的新组件

import { StyleSheet, Text, View } from 'react-native';
import Feather from 'react-native-vector-icons/Feather';

const ProfileHeaderTitle = ({ name }) => {
    return (
        <View style={styles.container}>
            <Feather name="user" size={24} color="#4B4942" />
            <Text style={styles.title}>{name}</Text>
        </View>
    )
}

const styles = StyleSheet.create({
    container: {
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between',
        gap: 10
    },
    title: {
        fontSize: 16,
        fontWeight: 'bold',
        color: '#4B4942'
    },

});

export default ProfileHeaderTitle;Code language: JavaScript (javascript)

步骤 3. 修改 App.js 以使用 ProfileHeaderTitle 组件作为 Profile 屏幕的标题

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Home, Profile } from './screens/index';
import ProfileHeaderTitle from './components/ProfileHeaderTitle';

const Stack = createNativeStackNavigator();

export default function App() {

  return (
    <NavigationContainer>
      <Stack.Navigator
        initialRouteName="Home"
        screenOptions={{
          headerStyle: {
            backgroundColor: '#FFD966',
          },
          headerTintColor: '#4B4942',
          headerTitleStyle: {
            fontWeight: 'bold',
          }
        }}>
        <Stack.Screen
          name="Home"
          component={Home}
          options={{
            title: 'Welcome'
          }}
        />
        <Stack.Screen
          name="Profile"
          component={Profile}
          options={({ route }) => ({
            headerTitle: () => <ProfileHeaderTitle name={route.params.name} />,
          })}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}Code language: JavaScript (javascript)

总结

  • 使用 React Navigation 库来管理和在屏幕之间进行导航。
本教程是否有用?