分頁導覽
分頁導覽可能是行動應用程式最常見的導覽樣式。分頁可能是位於畫面上方或下方(甚至取代標題)的標籤。
本指南包含 createBottomTabNavigator
。你也可以使用 createMaterialBottomTabNavigator
和 createMaterialTopTabNavigator
在應用程式中新增分頁。
在繼續之前,請先安裝 @react-navigation/bottom-tabs
- npm
- Yarn
- pnpm
npm install @react-navigation/bottom-tabs
yarn add @react-navigation/bottom-tabs
pnpm add @react-navigation/bottom-tabs
分頁導覽的最小範例
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
自訂外觀
這類似於如何自訂堆疊導覽器 - 在初始化分頁導覽器時,會設定一些屬性,而其他屬性則可以在 選項
中按畫面自訂。
// You can import Ionicons from @expo/vector-icons/Ionicons if you use Expo or
// react-native-vector-icons/Ionicons otherwise.
import Ionicons from 'react-native-vector-icons/Ionicons';
// (...)
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? 'ios-information-circle'
: 'ios-information-circle-outline';
} else if (route.name === 'Settings') {
iconName = focused ? 'ios-list' : 'ios-list-outline';
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
來分析一下
tabBarIcon
是底部分頁導覽器的支援選項。因此,我們知道可以在選項
prop 中對我們的畫面元件使用它,但在這種情況下,選擇將它放在Tab.Navigator
的screenOptions
prop 中,以便集中管理圖示組態,以簡化操作。tabBarIcon
是給予focused
狀態、color
和size
參數的函數。如果深入查看組態,您會看到tabBarActiveTintColor
和tabBarInactiveTintColor
。它們預設為 iOS 平台預設值,但您可以在這裡變更它們。傳遞給tabBarIcon
的color
是根據focused
狀態(已聚焦為活動中)是為活動中還是非活動中的顏色。size
是分頁欄預期的圖示大小。- 閱讀 完整的 API 參考 以進一步瞭解
createBottomTabNavigator
組態選項。
在圖示上新增徽章
有時我們希望在某些圖示上新增徽章。您可以使用 tabBarBadge
選項 來執行這項工作
<Tab.Screen name="Home" component={HomeScreen} options={{ tabBarBadge: 3 }} />
從 UI 角度來看,此元件已準備好可以使用,但您仍需要找出某種方式,從其他地方正確傳遞徽章計數,例如使用 React Context、Redux、MobX 或 事件發射器。
在分頁之間跳轉
從一個分頁切換到另一個分頁有熟悉的 API - navigation.navigate
。
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<Button
title="Go to Settings"
onPress={() => navigation.navigate('Settings')}
/>
</View>
);
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
);
}
每個分頁的堆疊導覽器
通常,分頁不會只顯示一個畫面 - 例如,在您的 Twitter 動態中,您可以輕觸推文,它會在分頁中帶您前往一個包含所有回覆的新畫面。您可以將此視為每個分頁中都有獨立的導覽堆疊,這正是我們將在 React 導覽中對其進行建模的方式。
import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function DetailsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details!</Text>
</View>
);
}
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
const HomeStack = createNativeStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
);
}
const SettingsStack = createNativeStackNavigator();
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator screenOptions={{ headerShown: false }}>
<Tab.Screen name="HomeStack" component={HomeStackScreen} />
<Tab.Screen name="SettingsStack" component={SettingsStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
為什麼我們需要 TabNavigator,而不是 TabBarIOS 或其他元件?
許多人會嘗試使用獨立的標籤列元件,但沒有將它整合到 app 中所使用的導覽庫中。某些情況下,此作法並無不妥!不過我們在此要提醒您,這麼做可能會遇到一些令人沮喪且始料未及的問題。
舉例來說,React Navigation 的標籤導覽器會幫您處理 Android 的返回按鈕,然而獨立的元件通常不會處理。此外,如果您需要呼叫兩個不同的 API,開發人員 (也就是您) 會比較難執行「跳到這個標籤,然後前往這個畫面」等動作。最後,行動裝置的使用者介面有很多小小的設計細節,需要某些元件能察覺其他元件的配置或存在。例如,如果您有一個半透明的標籤列,則內容應該可以在其下方捲動,而且捲動檢視會在底部有一個內嵌項目,其高度等於標籤列的高度,這樣您就能看到所有內容。雙擊標籤列會讓目前活動的導覽堆疊跳到堆疊最上層,再點一次會讓該堆疊的目前活動捲動檢視捲動到最上層。儘管 React Navigation 目前還沒有內建所有這些行為,但將來會有的,如果您使用獨立的標籤檢視元件,這些功能您一個都用不到。