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

时间:2019-02-15 09:06:35

标签: javascript reactjs react-native react-navigation

我知道之前曾有人问过这个问题,但仅适用于旧版本的react-navigation。从那以后,一些事情发生了变化。 createBottomTabNavigator使得创建底部导航器的速度大大提高,并且功能jumpToIndex()不再存在。

我的问题是如何创建类似Instagram的底部标签,其中第一,第二,第四和第五个导航按钮的作用类似于常规标签导航器,而中间按钮(screen3)打开模式{{1} }。

我已经使用screen3ModalcreateBottomTabNavigator在react-navigation 3.x.x中进行了尝试。

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 />; } }

5 个答案:

答案 0 :(得分: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 :(得分: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>

答案 2 :(得分:0)

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

这是经过全面测试的解决方案:

  1. 通过包括选项卡堆栈和要打开的模式导航堆栈来设置您的应用容器:
  const FinalTabsStack = createStackNavigator(
    {
      tabs: TabNavigator,
      screen1: Screen1Navigator,
    }, {
      mode: 'modal',
    }
  )
  1. 使用this指南中的标签堆栈创建应用容器

  2. TabNavigatorcreateBottomTabNavigator内,返回特定选项卡(screen3)的空组件(以关闭react-navigator的导航),并手动处理{{1}内的选项卡},为其创建自定义组件。

defaultNavigationOptions
  1. 使用TouchableWithoutFeedback和onPress在自定义标签组件 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组件:
Screen3Tab
  1. 一旦您赶上onPress调度Redux事件
  <TouchableWithoutFeedback onPress={this.onPress}>
    <Your custom tab component here />
  </TouchableWithoutFeedback>

  1. 使用Navigation Service处理已调度事件。我正在使用 onPress = () => { this.props.dispatch({ type: 'NAVIGATION_NAVIGATE', payload: { key: 'screen3', routeName: 'screen3', }}) }
redux-saga

有点复杂,但是可以用。

答案 3 :(得分:0)

我发现了一种基于this github issue的更好的解决方案。 您只需要添加特定的选项卡配置,在您的情况下screen3中,就可以看到事件NavigationOptions(您已经拥有了),但是,您必须将其作为参数接收,因为没有任何上下文可用于this,如您所用。要更正您编写的第一个代码,我将其更改为此,并且可以正常工作:

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

答案 4 :(得分:0)

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

就我而言,我想以iOS 13的演示文稿样式在iOS中打开一个模式,我所做的是防止出现以下默认操作

   <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的Tab导航器是 otherstacknavigation 中的屏幕之一,用于以下导航。

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;

您可以像下面一样导入 TransitionPresets

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

因此,就我而言,我有第一个主堆栈导航器,即上面的MainStack。它还有另一个堆栈导航器,它是MainStack上方的otherstacknavigation。该其他堆栈导航具有一个屏幕,该屏幕的组件为Tab导航器。上面代码中的Tab.Screen来自该Tab导航器。现在,从该标签导航器的一个标签中,我导航到MainStack中的“ modelscreen”。我必须创建此MainStack导航器才能实现此功能,否则我的代码将从otherstacknavigation开始。因为,ModalPresentationIOS只能应用于堆栈级别,而不能应用于屏幕级别。

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