我知道这个问题以前有人问过,但仅适用于旧版本的反应导航。从那以后,一些事情发生了变化。createBottomTabNavigator
使创建底部导航器的速度要快得多,并且函数jumpToIndex()
不再存在。
我的问题是如何创建一个类似Instagram的底部选项卡,其中第一个,第二个,第四和第五个导航按钮的作用类似于通常的选项卡导航器,中间按钮(screen3
)打开模态screen3Modal
。
我已经在反应导航 3.x.x 中使用createBottomTabNavigator
和createStackNavigator
尝试过它。
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 />;
}
}
好吧,我花了几个小时来解决这个问题。
这是完全工作和测试的解决方案:
- 通过包含选项卡堆栈和要打开的模式导航堆栈来设置应用容器:
const FinalTabsStack = createStackNavigator(
{
tabs: TabNavigator,
screen1: Screen1Navigator,
}, {
mode: 'modal',
}
)
根据本指南创建具有选项卡堆栈的应用程序容器
在
TabNavigator
内createBottomTabNavigator
为特定选项卡(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} />;
}
},
}),
- 在
- 自定义选项卡组件内手动处理单击,
Screen3Tab
与 TouchableWithoutFeedback 和 onPress。在屏幕3选项卡组件中:
<TouchableWithoutFeedback onPress={this.onPress}>
<Your custom tab component here />
</TouchableWithoutFeedback>
- 一旦你赶上新闻调度 redux 事件
onPress = () => {
this.props.dispatch({ type: 'NAVIGATION_NAVIGATE', payload: {
key: 'screen3',
routeName: 'screen3',
}})
}
- 使用导航服务处理调度事件。我正在使用
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.*,我认为它已经回答了在这种情况下可能出现的多个问题。