React-Navigation 3:使用 createBottomTabNavigator 和 createStack



我知道这个问题以前有人问过,但仅适用于旧版本的反应导航。从那以后,一些事情发生了变化。createBottomTabNavigator使创建底部导航器的速度要快得多,并且函数jumpToIndex()不再存在。

我的问题是如何创建一个类似Instagram的底部选项卡,其中第一个,第二个,第四和第五个导航按钮的作用类似于通常的选项卡导航器,中间按钮(screen3)打开模态screen3Modal

我已经在反应导航 3.x.x 中使用createBottomTabNavigatorcreateStackNavigator尝试过它。

import React, { Component, } from 'react';
import { createBottomTabNavigator, createStackNavigator, createAppContainer, } from 'react-navigation';
import { Screen1, Screen2, Screen3, Screen4, Screen5 } from './screens';
const TabNavigator = createBottomTabNavigator({
screen1: { screen: Screen1, },
screen2: { screen: Screen2, },
screen3: { 
screen: () => null, 
navigationOptions: () => ({
tabBarOnPress: () => this.props.navigation.navigate('screen3Modal')
})
},
screen4: { screen: Screen4, },
screen5: { screen: Screen5, },
});
const StackNavigator = createStackNavigator({
Home: { screen: TabNavigator },
screen3Modal: { screen: Screen3, },
},
{
initialRouteName: 'Home',
});
const StackNavigatorContainer = createAppContainer(StackNavigator);
export default class App extends Component {
render() {
return <StackNavigatorContainer />;
}
}

此代码创建选项卡导航和模式导航。模式可以从另一个屏幕打开,但它不能在选项卡导航器中工作。我收到错误消息undefined is not an object (evaluating '_this.props.navigation')

我找到了一个相对简单的解决方案: 使用display:"none"隐藏原始导航栏

const TabNavigator = createBottomTabNavigator(
{
screen1: Screen1,
screen2: Screen2,
screen4: Screen4,
screen5: Screen5,
}, {
tabBarOptions: {
style: { display: "none", }
}
},
);
const StackNavigator = createStackNavigator(
{
Home: TabNavigator,
screen3: Screen3
}, {
mode: 'modal',
}
)
export default createAppContainer(StackNavigator);

并在每个屏幕上创建一个新的导航栏

<View style={{ flexDirection: "row", height: 50, justifyContent: "space-evenly", alignItems: "center", width: "100%" }}>
<TouchableOpacity onPress={() => this.props.navigation.navigate("screen1")}><Text>1</Text></TouchableOpacity>
<TouchableOpacity onPress={() => this.props.navigation.navigate("screen2")}><Text>2</Text></TouchableOpacity>
<TouchableOpacity onPress={() => this.props.navigation.navigate("screen3")}><Text>3</Text></TouchableOpacity>
<TouchableOpacity onPress={() => this.props.navigation.navigate("screen4")}><Text>4</Text></TouchableOpacity>
<TouchableOpacity onPress={() => this.props.navigation.navigate("screen5")}><Text>5</Text></TouchableOpacity>
</View>

您可以将所有内容包装在同一个 StackNavigator 中,这样您就可以轻松导航到其他路由。在这里,我将 screen3 作为默认路由传递,但您可以将其更改为您想要的任何内容。

import React, { Component, } from 'react';
import { createBottomTabNavigator, createStackNavigator, createAppContainer, } from 'react-navigation';
import { Screen1, Screen2, Screen3, Screen4, Screen5 } from './screens';
const TabNavigator = createBottomTabNavigator({
screen1: { screen: Screen1, },
screen2: { screen: Screen2, },
screen3: { screen: () => null, }, //this.props.navigation.navigate('screen3Modal')
screen4: { screen: Screen4, },
screen5: { screen: Screen5, },
});
const StackNavigator = createStackNavigator({
Home: { screen: TabNavigator },
screen3Modal: { screen: Screen3, },
},
{
initialRouteName: 'screen3Modal',
});
const StackNavigatorContainer = createAppContainer(StackNavigator);
export default class App extends Component {
render() {
return <StackNavigatorContainer />;
}
}

好吧,我花了几个小时来解决这个问题。

这是完全工作和测试的解决方案:

  1. 通过包含选项卡堆栈和要打开的模式导航堆栈来设置应用容器:
const FinalTabsStack = createStackNavigator(
{
tabs: TabNavigator,
screen1: Screen1Navigator,
}, {
mode: 'modal',
}
)
  1. 根据本指南创建具有选项卡堆栈的应用程序容器

  2. TabNavigatorcreateBottomTabNavigator为特定选项卡(screen3)返回空组件(以关闭通过反应导航器导航),并通过为其创建自定义组件在defaultNavigationOptions内手动处理选项卡。

const TabNavigator = createBottomTabNavigator({
screen1: Screen1Navigator,
screen2: Screen2Navigator,
screen3: () => null,
screen4: Screen4Navigator,
screen5: Screen5Navigator,
}
defaultNavigationOptions: ({ navigation }) => ({
mode: 'modal',
header: null,
tabBarIcon: ({ focused }) => {
const { routeName } = navigation.state;
if (routeName === 'screen3') {
return <Screen3Tab isFocused={focused} />;
}
},
}),
  1. 自定义选项卡组件内手动处理单击,Screen3Tab与 TouchableWithoutFeedback 和 onPress。在屏幕3选项卡组件中:
<TouchableWithoutFeedback onPress={this.onPress}>
<Your custom tab component here />
</TouchableWithoutFeedback>
  1. 一旦你赶上新闻调度 redux 事件
onPress = () => {
this.props.dispatch({ type: 'NAVIGATION_NAVIGATE', payload: {
key: 'screen3',
routeName: 'screen3',
}})
}
  1. 使用导航服务处理调度事件。我正在使用redux-saga
NavigationService.navigate(action.payload);

有点复杂,但有效。

我根据这个 github 问题找到了更好的解决方案。 您只需要添加特定的选项卡配置,在您的情况下 screen3 事件导航选项(您已经拥有它),您非常接近,但是,您必须将导航作为参数接收,因为没有任何上下文供您使用它时this。要更正您编写的第一个代码,我会将其更改为此代码,它将起作用:

navigationOptions: ({ navigation }) => ({
tabBarOnPress: ({ navigation }) => {
navigation.navigate("screen3Modal");
}
})

可以做的是阻止Tab Press 事件的默认操作,并使用所需的动画导航到所需的屏幕。

就我而言,我想在iOS中以来自iOS 13的演示风格打开一个模态。 我所做的是阻止如下所示的默认操作

<Tab.Screen name="screen1" 
component={ EmptyScreen } // empty screen becuase I want nothing to present here so it was a component that returns null which is given bellow   
listeners={({ navigation, route }) => ({
tabPress: e => {
e.preventDefault();
navigation.navigate('modalscreen');
},
})} />

const EmptyScreen = () => {
return null
}

上面代码中使用的"modelscreen"来自一个看起来像波纹管的导航堆栈。上面代码中 Tab.Screen 的选项卡导航器是其他堆栈导航中的屏幕之一,用于下面的导航。

const MainStack = ({ initialRoute }) => {
return (
<Stack.Navigator 
initialRouteName="otherstacknavigation" 
screenOptions={{
headerShown: false,
gestureEnabled: true,
cardOverlayEnabled: true,
...TransitionPresets.ModalPresentationIOS
}}>
<Stack.Screen name='modalscreen' 
component={modalscreen}
options={{
headerShown: false
}} />
<Stack.Screen name='otherstacknavigation' 
component={otherstacknavigation}
initialParams={{ initialRoute: initialRoute }}/>
</Stack.Navigator>
);
}
export default MainStack;

您可以导入像波纹管这样的过渡预设;

import { createStackNavigator, TransitionPresets } from '@react-navigation/stack'

所以,就我而言,我有第一个主堆栈导航器,即上面的 MainStack。它有另一个堆栈导航器,它是MainStack上方的其他堆栈导航。该其他堆栈导航有一个屏幕,其组件是选项卡导航器。和上面的代码中的Tab.Screen来自该选项卡导航器。现在,从此选项卡导航器中的一个选项卡中,我正在导航到 MainStack 中的"模型屏幕"。我必须创建这个 MainStack 导航器才能实现此功能,否则我的代码将从其他堆栈导航开始。因为,ModalPresentationIOS只能应用于堆栈级别,而不能应用于屏幕级别。

我正在使用 react-navigation-5.*,我认为它已经回答了在这种情况下可能出现的多个问题。

相关内容

  • 没有找到相关文章

最新更新