在 React Native 中将堆栈导航器与抽屉式导航器相结合

问题描述 投票:0回答:1

所以我是反应原生和反应导航的新手。

我正在构建一个有 7 个主屏幕的应用程序:

  • HomeScreen、ProfileScreen、CocktailDetailScreen 和 PublishRecipeScreen(我希望能够通过抽屉导航器访问)。
  • LandingScreen、LoginScreen 和 RegisterScreen(我不想在抽屉式导航器中显示。我只想在用户未登录时显示 LandingScreen,如果用户想要登录或注册,则显示另一个) ).

我已经能够建立一个工作正常的堆栈导航器,但我不明白如何将其与我想要的抽屉导航器结合起来。我尝试了不同的方法,但出现了如下错误:

The action 'OPEN_DRAWER' was not handled by any navigator.
Is your screen inside a Drawer navigator?

Uncaught Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them.

这是我到目前为止的代码。 App.tsx

import { SafeAreaProvider } from 'react-native-safe-area-context'

import useCachedResources from './hooks/useCachedResources'
import Navigation from './navigation'

export default function App() {
  const isLoadingComplete = useCachedResources()

  if (!isLoadingComplete) {
    return null
  } else {
    return (
      <SafeAreaProvider>
        <Navigation />
      </SafeAreaProvider>
    )
  }
}

(导航)index.tsx

import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import * as React from 'react'

import LandingScreen from '../screens/LandingScreen'
import LoginScreen from '../screens/LoginScreen'
import RegisterScreen from '../screens/RegisterScreen'
import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'

import Header from '../components/Header'
import DrawerNavigator from '../components/DrawerNavigator'

import { RootStackParamList } from '../types'

export default function Navigation() {

  const Stack = createNativeStackNavigator<RootStackParamList>()

  return (
    <NavigationContainer>

      <Stack.Navigator >
        <Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
        <Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
        <Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />
        <Stack.Screen name='HomeScreen' component={HomeScreen} options={{ header: () => <Header/> }} />
        <Stack.Screen name='ProfileScreen' component={ProfileScreen} options={{ header: () => <Header/> }} />
        <Stack.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} options={{ header: () => <Header/> }} />
        <Stack.Screen name='PublishRecipeScreen' component={PublishRecipeScreen} options={{ header: () => <Header/> }} />
      </Stack.Navigator>
  
    </NavigationContainer>
  )
}

标题.tsx

import React from 'react'
import { useNavigation } from '@react-navigation/native'
import { useDrawerStatus } from '@react-navigation/drawer'
import { DrawerActions } from '@react-navigation/native'

import { StyleSheet, Text, View } from 'react-native'
import { AntDesign } from '@expo/vector-icons'

const Header = () => {

const navigation = useNavigation()

  return (
    <View style={styles.container}>
        <Text style={styles.title} onPress={() => navigation.navigate('RegisterScreen')}>Mixr</Text>
        <View style={styles.iconContainer} >
            <AntDesign name='user' style={styles.icon} size={30} color='white' onPress={() => navigation.dispatch(DrawerActions.openDrawer())} />
        </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    backgroundColor: '#E51C27',
    alignSelf: 'stretch'
  },
  title: {
    fontSize: 40,
    fontWeight: 'bold',
    marginTop: 6,
    marginBottom: 6,
    marginLeft: 10
  },
  iconContainer: {
    backgroundColor: 'black',
    borderBottomLeftRadius: 50,
    borderBottomRightRadius: 50,
    borderTopLeftRadius: 50,
    borderTopRightRadius: 50,
    marginRight: 10
  },
  icon: {
    padding: 5
  }
})

export default Header

DrawerNavigator.tsx

import React from 'react'
import { createDrawerNavigator, useDrawerStatus } from '@react-navigation/drawer'
import { NavigationContainer } from '@react-navigation/native'

import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'

const DrawerNavigator = () => {

const Drawer = createDrawerNavigator()

  return (
    <NavigationContainer>
        <Drawer.Navigator>
            <Drawer.Screen name='HomeScreen' component={HomeScreen} />
            <Drawer.Screen name='ProfileScreen' component={ProfileScreen} />
            <Drawer.Screen name='CocktailDetailScreen' component={CocktailDetailScreen} />
            <Drawer.Screen name='PublishRecipeScreen' component={PublishRecipeScreen} />
        </Drawer.Navigator>
    </NavigationContainer>
  )
}

export default DrawerNavigator

我想在所有页面(HomeScreen、ProfileScreen、CocktailDetailScreen 和 PublishRecipeScreen)中显示标题,并从该标题能够打开/关闭抽屉。我不太明白如何将堆栈导航器与抽屉链接起来。

从更理论的角度来看,我不太理解堆栈导航器、抽屉和其他选项(如选项卡或底部导航器)之间的区别。

我的意思是,除此之外,抽屉导航器显示在抽屉中,底部导航器显示在底部。它们之间有概念上的区别吗?

完整代码可以在这里找到:https://github.com/coccagerman/mixr

react-native expo react-navigation react-navigation-stack react-navigation-drawer
1个回答
2
投票

我想我已经明白了。

我所做的是将抽屉导航器嵌套在堆栈导航器中。

为此,我将抽屉导航器作为我希望它位于的每个屏幕的组件传递。

像这样: (导航)index.tsx

import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import * as React from 'react'

import LandingScreen from '../screens/LandingScreen'
import LoginScreen from '../screens/LoginScreen'
import RegisterScreen from '../screens/RegisterScreen'

import Header from '../components/Header'
import DrawerNavigator from '../components/DrawerNavigator'

import { RootStackParamList } from '../types'

export default function Navigation() {

  const Stack = createNativeStackNavigator<RootStackParamList>()

  return (
    <NavigationContainer>

      <Stack.Navigator >
        <Stack.Screen name='LandingScreen' component={LandingScreen} options={{headerShown: false}} />
        <Stack.Screen name='LoginScreen' component={LoginScreen} options={{headerShown: false}} />
        <Stack.Screen name='RegisterScreen' component={RegisterScreen} options={{headerShown: false}} />

        <Stack.Screen name='HomeScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
        <Stack.Screen name='ProfileScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
        <Stack.Screen name='CocktailDetailScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
        <Stack.Screen name='PublishRecipeScreen' component={DrawerNavigator} options={{ header: () => <Header/> }} />
      </Stack.Navigator>
    </NavigationContainer>
  )
}

在抽屉导航器中,我将相应的屏幕组件分配给每个屏幕: DrawerNavigator.tsx 从“反应”导入反应 从 '@react-navigation/drawer' 导入 { createDrawerNavigator }

import HomeScreen from '../screens/HomeScreen'
import ProfileScreen from '../screens/ProfileScreen'
import CocktailDetailScreen from '../screens/CocktailDetailScreen'
import PublishRecipeScreen from '../screens/PublishRecipeScreen'

const DrawerNavigator = () => {

const Drawer = createDrawerNavigator()

  return (
    <Drawer.Navigator>
        <Drawer.Screen name='Home' component={HomeScreen} options={{headerShown: false}} />
        <Drawer.Screen name='Profile' component={ProfileScreen} options={{headerShown: false}} />
        <Drawer.Screen name='CocktailDetail' component={CocktailDetailScreen} options={{headerShown: false}} />
        <Drawer.Screen name='PublishRecipe' component={PublishRecipeScreen} options={{headerShown: false}} />
    </Drawer.Navigator>
  )
}

export default DrawerNavigator

我仍然觉得这有点令人困惑,我想可能有一种更简单的方法来写这个。

我在这个主题上找到的有用资源:

© www.soinside.com 2019 - 2024. All rights reserved.