背景
上一篇文章详细讲解了react-navigation
的使用,这篇文章主要说一下Stack Navigation
与Tab Navigation
嵌套的问题。
在iOS原生开发中,一般是在TabController
里嵌套NavigationController
,也就是说底部导航控制器里放多个堆栈导航控制器,每个堆栈导航控制器控制有独立的堆栈和状态。
但如果在使用react-navigation
进行这种嵌套方式,由于根控制器是底部的TabNavigation
,每次跳转到子控制器时,底部的导航栏不会隐藏。官方文档说可以用属性更改的方法隐藏底部导航栏,但不推荐,会影响性能。因此本文主要讲解如何使用堆栈导航器中嵌套底部导航控制器来解决这个问题。
实现方式
首先将Main
控制器放入Stack Navigation
中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class App extends Component {
render() { return ( <NavigationContainer> <Stack.Navigator> <Stack.Screen key="Main" name="Main" component={Main} options={({route}) => ({ headerTitle: route.name })} /> </Stack.Navigator> </NavigationContainer> ); } }
|
然后实现Main
控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| const Main = ({navigation, route}) => {
return ( <Tab.Navigator screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => {`` return ( <Image style = {{ width: 25, height: 25 }} source = {this.iconImage(route, focused)} />); }, })} tabBarOptions={{ activeTintColor: '#32B7FF', inactiveTintColor: 'gray', }} > <Tab.Screen name="Home" component={HomeScreen} options={{title: 'Home'}}/> <Tab.Screen name="Settings" component={SettingsScreen} options={{title: 'Settings'}}/> </Tab.Navigator> ); }
function iconImage(route, focused) { let image; if (route.name === 'Home') { image = focused ? require('../../images/homePage_sel.png') : require('../../images/homePage_nor.png'); } else { image = focused ? require('../../images/setting_sel.png') : require('../../images/setting_nor.png'); } return image; }
|
上面Home
和Setting
页面的实现这里就不再赘述,实现之后运行会发一Home
和Setting
顶部导航栏的标题和样式都是相同的,也就是Main
控制器的。这是由于Tab Navigation
作为Stack Navigation
的根控制器,顶部导航栏的标题都是按照根控制器的设置来显示的。要实现Tab Navigaiton
的子控制器都有自己的独立顶部导航栏,需要使用React
的Hook
方法,在return
前面加上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| React.useLayoutEffect(() => { navigation.setOptions({ headerTitle: this.getHeaderTitle(route), headerRight: this.getHeaderRight(route), headerLeft: this.getHeaderLeft(route), }); }, [navigation, route]); getHeaderTitle(route) { const routeName = getFocusedRouteNameFromRoute(route) ?? 'Home'; switch (routeName) { case 'Home': return '首页'; case 'Settings': return '系统设置'; } }
|
这里使用了React
的useLayoutEffect
方法,这个方法会从DOM
里读取布局并同步把新布局添加了布局更新计划中,等一下次重新绘制就会更新上去。在方法中通过route
名称动态地改变了导航栏的标题和左右侧的按钮,当底部导航栏按钮被点击进行切换时,顶底的导航栏显示也会同步更新。
至此,Stack Navigation
和Tab Navigation
嵌套时保证跳转时隐藏底部导航栏的最佳实践就完成了。