第一节:导航器基本介绍
什么是导航器?
在移动应用中,通常需要多个页面来实现复杂的功能。例如:
- iOS 的设置应用采用堆栈式导航。
- 照片应用使用底部标签导航。
- Android 的联系人应用使用抽屉式导航。
导航器的作用是管理页面之间的跳转、传参、记录导航历史,并提供统一的标题栏等组件。React Navigation 是 React Native 官方推荐的导航解决方案。它完全基于 React Native 组件实现,具有高度的灵活性和定制能力,性能表现流畅。
React Navigation v5 是目前推荐的版本。与之前的版本相比,v5 将导航器拆分为独立的包,并采用组件化的方式实现,支持动态配置导航。这种设计更符合 React 的理念,也更易于使用。
第二节:安装 React Navigation
在本节中,我们将学习如何在项目中安装 React Navigation。
安装步骤
-
安装核心包和依赖项
yarn add @react-navigation/native yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-viewreact-native-reanimated:高性能动画库。react-native-gesture-handler:跨平台手势处理库。react-native-screens:用于优化性能的屏幕组件。react-native-safe-area-context:提供安全区域支持,避免刘海屏等问题。@react-native-community/masked-view:用于堆栈导航器的蒙版视图。
-
配置 Android 项目
-
如果使用 React Native 0.60 及以上版本,自动链接功能会处理依赖项,无需手动运行
react-native link。 -
如果需要支持 iOS,运行以下命令:
cd ios && pod install && cd ..
-
-
修改 Android 原生代码
-
在
android/app/build.gradle的dependencies中添加:implementation 'androidx.appcompat:appcompat:1.1.0-rc01' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02' -
修改
android/app/src/main/java/MainActivity.java,支持手势系统:import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactRootView; import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; @Override protected ReactActivityDelegate createReactActivityDelegate() { return new ReactActivityDelegate(this, getMainComponentName()) { @Override protected ReactRootView createRootView() { return new RNGestureHandlerEnabledRootView(MainActivity.this); } }; }
-
-
在
index.js中添加import 'react-native-gesture-handler';如果不添加这一行,应用在生产环境中可能会闪退。
第三节:堆栈式导航器
堆栈式导航器的使用
-
安装堆栈式导航器
yarn add @react-navigation/stack -
创建页面组件
在
pages文件夹中创建Home.tsx和Detail.tsx,它们是普通的 React Native 组件。 -
配置导航器
在
navigator/index.tsx中创建导航器:import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; export type RootStackParamList = { Home: undefined; Detail: undefined; }; const Stack = createStackNavigator<RootStackParamList>(); const Navigator = () => ( <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={Home} /> <Stack.Screen name="Detail" component={Detail} /> </Stack.Navigator> </NavigationContainer> ); export default Navigator; -
配置标题栏
-
设置全局样式:
<Stack.Navigator screenOptions={{ headerTitleAlign: 'center', headerStyleInterpolator: HeaderStyleInterpolators.forUIKit, cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS, gestureEnabled: true, gestureDirection: 'horizontal', headerStyle: { ...Platform.select({ android: { elevation: 0, borderBottomWidth: StyleSheet.hairlineWidth, }, }), }, }} > -
为页面设置标题:
<Stack.Screen name="Home" component={Home} options={{ headerTitle: '首页' }} /> <Stack.Screen name="Detail" component={Detail} options={{ headerTitle: '详情页' }} />
-
-
页面跳转与传参
-
在
Home页面中:navigation.navigate('Detail', { id: 10 }); -
在
Detail页面中接收参数:const { params } = route; console.log(params.id);
-
第四节:标签导航器
标签导航器的使用
-
安装标签导航器
yarn add @react-navigation/bottom-tabs -
创建标签导航器
在
navigator/BottomTabs.tsx中创建底部标签导航器:import React from 'react'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; export type BottomTabParamList = { Home: undefined; Listen: undefined; Found: undefined; Account: undefined; }; const Tab = createBottomTabNavigator<BottomTabParamList>(); const BottomTabs = () => ( <Tab.Navigator tabBarOptions={{ activeTintColor: '#f86442' }}> <Tab.Screen name="Home" component={Home} options={{ tabBarLabel: '首页' }} /> <Tab.Screen name="Listen" component={Listen} options={{ tabBarLabel: '我听' }} /> <Tab.Screen name="Found" component={Found} options={{ tabBarLabel: '发现' }} /> <Tab.Screen name="Account" component={Account} options={{ tabBarLabel: '我的' }} /> </Tab.Navigator> ); export default BottomTabs; -
导航器嵌套
-
在堆栈导航器中嵌套标签导航器:
<Stack.Screen name="BottomTabs" component={BottomTabs} /> -
在标签导航器中嵌套堆栈导航器:
<Tab.Screen name="Stack" component={Stack} />
-
-
动态修改标题栏
使用
route.state动态获取当前页面的标题:function getHeaderTitle(route) { const routeName = route.state ? route.state.routes[route.state.index].name : route.params?.screen || 'Home'; switch (routeName) { case 'Home': return '首页'; case 'Listen': return '我听'; case 'Found': return '发现'; case 'Account': return '我的'; } } navigation.setOptions({ headerTitle: getHeaderTitle(route), });