react native navigation 隱藏 bottomTab
前言
在做 react-native app 時, 用到了 react navigation 的 bottom tab navigation, 但是在某些情況下需要控制 bottom tab bar 的顯示和隱藏。
試了很多中方法,最後比較簡單的方式是修改nodeModels裏面的源碼。
本文 react-native 版本爲 0.59.8 , react-navigation 版本爲 3.10.1
開始
核心思想是從 nodemodels 中找到渲染 bottom tab 的代碼,直接的來控制它的顯示隱藏。
找到代碼文件爲 nodemodels的 react-navigation-tabs/src/navigators/createBottomTabNavigator.js
爲該文件中的類添加 state hidden=false;
在該類的 componentDidMount 中, 將hidden值的控制權 掛到 global.func上,
componentDidMount() {
global.func.showBottomTab = () => {
this.setState({
hidden: false
})
}
global.func.hideBottomTab = () => {
this.setState({
hidden: true
})
}
}
在該類的 render 中, 判斷 this.state.hidden, 若 true, 則直接return ,即可實現隱藏
在需要隱藏 bottom tab 時, 只需要調用 global.func.hideBottom() 即可,項目中任何位置均可調用;
需要顯示時,調用 global.func.showBottom();
文件路徑爲 react-navigation-tabs/src/navigators/createBottomTabNavigator.js,修改後的代碼參考:
/* @flow */
// 使用該文件取覆蓋 nodemodels的 react-navigation-tabs/src/navigators/createBottomTabNavigator.js
/* @flow */
import * as React from 'react';
import { View, StyleSheet } from 'react-native';
import { polyfill } from 'react-lifecycles-compat';
// eslint-disable-next-line import/no-unresolved
import { ScreenContainer } from 'react-native-screens';
import createTabNavigator, {
type InjectedProps,
} from '../utils/createTabNavigator';
import BottomTabBar, { type TabBarOptions } from '../views/BottomTabBar';
import ResourceSavingScene from '../views/ResourceSavingScene';
type Props = InjectedProps & {
getAccessibilityRole: (props: { route: any }) => string,
getAccessibilityStates: (props: { route: any }) => Array<string>,
lazy?: boolean,
tabBarComponent?: React.ComponentType<*>,
tabBarOptions?: TabBarOptions,
};
type State = {
loaded: number[],
};
class TabNavigationView extends React.PureComponent<Props, State> {
static defaultProps = {
lazy: true,
getAccessibilityRole: () => 'button',
getAccessibilityStates: ({ focused }) => (focused ? ['selected'] : []),
};
static getDerivedStateFromProps(nextProps, prevState) {
const { index } = nextProps.navigation.state;
return {
// Set the current tab to be loaded if it was not loaded before
loaded: prevState.loaded.includes(index)
? prevState.loaded
: [...prevState.loaded, index],
};
}
state = {
loaded: [this.props.navigation.state.index],
hidden: false
};
_renderTabBar = () => {
const {
tabBarComponent: TabBarComponent = BottomTabBar,
tabBarOptions,
navigation,
screenProps,
getLabelText,
getAccessibilityLabel,
getButtonComponent,
getAccessibilityRole,
getAccessibilityStates,
getTestID,
renderIcon,
onTabPress,
onTabLongPress,
} = 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}
onTabLongPress={onTabLongPress}
getLabelText={getLabelText}
getButtonComponent={getButtonComponent}
getAccessibilityLabel={getAccessibilityLabel}
getAccessibilityRole={getAccessibilityRole}
getAccessibilityStates={getAccessibilityStates}
getTestID={getTestID}
renderIcon={renderIcon}
/>
);
};
_jumpTo = (key: string) => {
const { navigation, onIndexChange } = this.props;
const index = navigation.state.routes.findIndex(route => route.key === key);
onIndexChange(index);
};
componentDidMount() {
global.func.showBottomTab = () => {
this.setState({
hidden: false
})
}
global.func.hideBottomTab = () => {
this.setState({
hidden: true
})
}
}
render() {
const { navigation, renderScene, lazy } = this.props;
const { routes } = navigation.state;
const { loaded } = this.state;
let tabBar = this._renderTabBar()
if (this.state.hidden) {
tabBar = <View></View>
}
return (
<View style={styles.container}>
<ScreenContainer 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}
isVisible={isFocused}
>
{renderScene({ route })}
</ResourceSavingScene>
);
})}
</ScreenContainer>
{tabBar}
</View>
);
}
}
polyfill(TabNavigationView);
const styles = StyleSheet.create({
container: {
flex: 1,
overflow: 'hidden',
},
pages: {
flex: 1,
},
});
export default createTabNavigator(TabNavigationView);