今天在項目中遇到一個問題,使用createBottomTabNavigator和createStackNavigator構建頁面導航。如圖1所示,底部導航欄每一個Tab都是一個stackNavigator,當我點擊圖中GIS地圖時,切換到其他Tab選項后再切換回來發現頁面依然停留在上次點擊GIS地圖頁面且地圖變黑了(圖 2)。為了解決這個問題,需要確保切換Tab選項時頁面停留在相應stackNavigator的初始頁面,也就是圖1中的頁面。據此,點擊圖1中GIS地圖時需要將底部導航欄隱藏,這樣當我們想切換Tab選項時只能先返回到初始頁面,也就是圖1中的頁面。
圖1
圖2
觀察createBottomTabNavigator的源碼可以發現this._renderTabBar()就是用來渲染底部導航欄的,點進去發現返回的是一個BottomTabBar組件。
render() {
const { navigation, renderScene, lazy } = this.props;
const { routes } = navigation.state;
const { loaded } = this.state;
return <View style={styles.container}>
<View style={styles.pages}>
{routes.map((route, index) => {
if (lazy && !loaded.includes(index)) {
// Don't render a screen if we've never navigated to it
return null;
}
const isFocused = navigation.state.index === index;
return <ResourceSavingScene key={route.key} style={[StyleSheet.absoluteFill, { opacity: isFocused ? 1 : 0 }]} isVisible={isFocused}>
{renderScene({ route })}
</ResourceSavingScene>;
})}
</View>
{this._renderTabBar()}
</View>;
}
_renderTabBar = () => {
const {
tabBarComponent: TabBarComponent = BottomTabBar,
tabBarOptions,
navigation,
screenProps,
getLabelText,
getAccessibilityLabel,
getButtonComponent,
getTestID,
renderIcon,
onTabPress
} = this.props;
const { descriptors } = this.props;
const { state } = this.props.navigation;
const route = state.routes[state.index];
const descriptor = descriptors[route.key];
const options = descriptor.options;
if (options.tabBarVisible === false) {
return null;
}
return <TabBarComponent {...tabBarOptions} jumpTo={this._jumpTo} navigation={navigation} screenProps={screenProps} onTabPress={onTabPress} getLabelText={getLabelText} getButtonComponent={getButtonComponent} getAccessibilityLabel={getAccessibilityLabel} getTestID={getTestID} renderIcon={renderIcon} />;
};
繼續觀察BottomTabBar的源碼發現其根據當前的路由路徑routes渲染一個包含有標簽與圖表的ButtonComponent組件。開啟調試模式觀察routes結構發現,routes是一個json對象,其routes字段為一個數組,表示當前stackNavigator中的頁面個數,當頁面位于如圖1所示的初始頁面時該數組長度為1,位于如圖2所示的頁面時該數組長度大于1。
const { routes } = navigation.state;
const tabBarStyle = [styles.tabBar, this._shouldUseHorizontalLabels() && !Platform.isPad ? styles.tabBarCompact : styles.tabBarRegular, style];
return <SafeAreaView style={tabBarStyle} forceInset={safeAreaInset}>
{routes.map((route, index) => {
const focused = index === navigation.state.index;
const scene = { route, focused };
const accessibilityLabel = this.props.getAccessibilityLabel({
route
});
const testID = this.props.getTestID({ route });
const backgroundColor = focused ? activeBackgroundColor : inactiveBackgroundColor;
const ButtonComponent = this.props.getButtonComponent({ route }) || TouchableWithoutFeedbackWrapper;
return <ButtonComponent key={route.key} onPress={() => onTabPress({ route })} testID={testID} accessibilityLabel={accessibilityLabel} style={[styles.tab, { backgroundColor }, this._shouldUseHorizontalLabels() ? styles.tabLandscape : styles.tabPortrait, tabStyle]}>
{this._renderIcon(scene)}
{this._renderLabel(scene)}
</ButtonComponent>;
})}
</SafeAreaView>;
初始頁面的routes
GIS地圖的routes
因此,可以在BottomTabBar組件中進行條件渲染,當頁面處于如圖2所示的頁面時返回一個空的View組件,代碼如下:
//點擊子頁面時隱藏底部導航欄
let number = 0;
for (var i = 0; i < routes.length; i++) {
if (routes[i].routes.length > 1) {
number = number + 1;
}
}
if (number != 0) {
return <View style={{
height: 30,
backgroundColor: '#FFFFFF'
}}/>
}
至此,可以實現點擊GIS地圖時隱藏底部導航欄的功能(圖3)。圖3