React-Navigation 3:使用createBottomTabNavigator和createStackNavigator打开模态

问题描述 投票:3回答:3

我知道之前已经问过这个问题,但仅限于旧版本的react-navigation。从那时起,一些事情发生了变化。 createBottomTabNavigator使创建底部导航器的速度更快,而且jumpToIndex()功能不再存在。

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

我使用createBottomTabNavigatorcreateStackNavigator在react-navigation 3.x.x中尝试过它。

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')

javascript reactjs react-native react-navigation
3个回答
1
投票

您可以将所有内容包装在同一个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
投票

我找到了一个相对简单的解决方案:用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>

0
投票

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

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

  1. 通过包含选项卡堆栈和打开模态导航堆栈来设置您的应用程序容器:
  const FinalTabsStack = createStackNavigator(
    {
      tabs: TabNavigator,
      screen1: Screen1Navigator,
    }, {
      mode: 'modal',
    }
  )
  1. 根据this指南创建具有该选项卡堆栈的应用程序容器
  2. TabNavigator中的createBottomTabNavigator内部返回特定选项卡的空组件(screen3)(通过react-navigator关闭导航)并通过为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. 使用TouchableWithoutFeedback&onPress在自定义选项卡组件Screen3Tab内手动单击。 Screen3Tab内部组件:
  <TouchableWithoutFeedback onPress={this.onPress}>
    <Your custom tab component here />
  </TouchableWithoutFeedback>

  1. 一旦你赶上onPress dispatch redux事件
  onPress = () => {
    this.props.dispatch({ type: 'NAVIGATION_NAVIGATE', payload: {
      key: 'screen3',
      routeName: 'screen3',
    }})
  }
  1. 使用Navigation Service处理调度事件。我正在使用redux-saga
  NavigationService.navigate(action.payload);

有点复杂,但有效。


0
投票

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

navigationOptions: ({ navigation }) => ({
  tabBarOnPress: ({ navigation }) => {
    navigation.navigate("screen3Modal");
  }
})
© www.soinside.com 2019 - 2024. All rights reserved.