當頁面很多時,可進一步透過巢狀路由來管理頁面,讓頁面架構更清楚。以 Google Podcast 為例,下面有一個 Bottom Navigation 。其中媒體庫的頁面中有四個連結「訂閱」、「待播清單」、「下載內容」、「紀錄」,點擊訂閱後則會進到訂閱頁。
稍加拆解會發現下方 Bottom Navigation 算一個 Navigator ,包含三個 Screen 「首頁」、「探索」、「媒體庫」。而媒體庫本身也算一個 Navigator ,包含四個 Screen 「訂閱」、「待播清單」、「下載內容」、「紀錄」。這就是所謂的巢狀路由。
現在讓我們嘗試撰寫一個巢狀路由架構。為了簡化複雜度,讓我們直接利用前面已經做好的 SettingsScreen 改寫,使他底下多出帳號管理 AccountScreen 和語言設定 LanguageScreen 。
創建 AccountScreen 和 LanguageScreen 。
function AccountScreen() {
return (
<View>
<Text>帳號管理</Text>
</View>
);
}
function LanguageScreen() {
return (
<View>
<Text>語言設定</Text>
</View>
);
}
接著改寫 SettingsScreen ,基本架構就像前面講過的 Stack Navigation ,只是為了方便判別他是個 Stack ,將元件名稱更改成 SettingsStack。 BottomNavigation 引入的元件,也別忘了一併更改名稱:
import {createNativeStackNavigator} from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function SettingsStack() {
return (
<Stack.Navigator>
<Stack.Screen name="AccountScreen" component={AccountScreen} />
<Stack.Screen name="LanguageScreen" component={LanguageScreen} />
</Stack.Navigator>
);
}
完成後, AccountScreen 和 LanguageScreen 就會被掛在 SettingStack 的路由之下。
為了讓進入 SettingStack 時,可以有一個菜單頁能進 AccountScreen 和 LanguageScreen ,可以再製作一個 SettingsMenuScreen 元件:
function SettingsMenuScreen({navigation}) {
return (
<View>
<TouchableOpacity onPress={() => navigation.navigate('AccountScreen')}>
<Text>帳號管理</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('LanguageScreen')}>
<Text>語言設定</Text>
</TouchableOpacity>
</View>
);
}
再引入 SettingStack 中:
function SettingStack() {
return (
<Stack.Navigator>
<Stack.Screen name="SettingsMenuScreen" component={SettingsMenuScreen} />
<Stack.Screen name="AccountScreen" component={AccountScreen} />
<Stack.Screen name="LanguageScreen" component={LanguageScreen} />
</Stack.Navigator>
);
}
最後,運用前面提過的 options 屬性,我們能把 Settings 這個 Header 隱藏。
function BottomeNavigation() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen
name="Settings"
component={SettingsStack}
options={{
headerShown: false,
headerTransparent: true,
headerBackground: () => null,
}}
/>
</Tab.Navigator>
);
}
運用上面所做的,來看一下巢狀路由有哪些特性:
最後補充一個特殊情況:要如何從一個 Stack ,進到另一個 Stack 中的巢狀路由下的子路由呢?
為了模擬出問題,我們建立一個 HomeStack ,並將他和 SettingsStack 一起掛在 BottomNavigation 底下:
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
</Stack.Navigator>
);
}
function BottomeNavigation() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStack} />
<Tab.Screen
name="Settings"
component={SettingsStack}
options={{
headerShown: false,
headerTransparent: true,
headerBackground: () => null,
}}
/>
</Tab.Navigator>
);
}
現在 HomeScreen 和 AccountScreen 分別被掛在 HomeStack 與 SettingsStack 之下。要從 HomeScreen 跳到 AccountScreen ,需要在第一個參數提供 Stack name ,在第二個參數附上有真正 Screen 名稱的物件。
function HomeScreen({navigation}) {
return (
<View>
<Text>Home</Text>
<TouchableOpacity
onPress={() =>
navigation.navigate('Settings', {screen: 'AccountScreen'})
}>
<Text>帳號管理</Text>
</TouchableOpacity>
</View>
);
}