React-Native - 屏幕之一上没有 header(堆栈 + 抽屉导航)
React-Native - no header on one of the screen (Stack + Drawer Navigation)
我的导航文件如下。所有注册到堆栈导航器的屏幕都有一个 header。使用抽屉导航器注册为第二个选项的一个屏幕根本没有 header (OrdersScreen)。我也尝试在 Stack 导航器下添加它的条目,但它没有改变任何东西。 OrderScreen 中的 setOptions 没有任何效果,因为没有显示 header。
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { Platform } from 'react-native';
import Colors from '../constants/Colors';
import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetailScreen from "../screens/shop/ProductDetailScreen";
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const AppNavigation = () => {
return(
<NavigationContainer>
<Drawer.Navigator initialRouteName="ShopNavigation">
<Drawer.Screen name="Products" component={ShopNavigation}/>
<Drawer.Screen name="Orders" component={OrdersScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
};
const ShopNavigation = () => {
return(
<Stack.Navigator>
<Stack.Screen
name="Products"
component={ProductsOverviewScreen}
options={{
title: 'All Products',
headerStyle: {
backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
},
headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
headerTitleStyle: {
fontFamily: 'open-sans-bold'
},
headerBackTitleStyle: {
fontFamily: 'open-sans'
}
}}
/>
<Stack.Screen name="Product Details" component={ProductDetailScreen} />
<Stack.Screen name="Cart" component={CartScreen} />
</Stack.Navigator>
);
};
export default AppNavigation;
OrderScreen如下:
import React, {useEffect} from 'react';
import {FlatList, View, Platform, Text, Button} from 'react-native';
import { useSelector } from 'react-redux';
import {HeaderButtons, Item} from "react-navigation-header-buttons";
import CustomHeaderButton from "../../components/UI/HeaderButton";
const OrdersScreen = (props) => {
const orders = useSelector(state => state.orders.orders);
useEffect(() => {
props.navigation.setOptions({
title: 'Your Orders',
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Orders"
iconName={Platform.OS === 'android' ? 'md-menu' : 'ios-menu'}
onPress={() => props.navigation.toggleDrawer()}
/>
</HeaderButtons>
),
});
},[])
return(
<View>
<Text>Orders screens</Text>
<Text>some text</Text>
<Text>Yet another</Text>
<Button title="toggle Drawer" onPress={() => props.navigation.toggleDrawer()} />
</View>
);
};
export default OrdersScreen;
Stack 导航中的默认屏幕 ProductsOverviewScreen 与 header 按钮和 header 图标配合使用效果很好。
import React, { useEffect } from 'react';
import { FlatList, Platform } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import ProductItem from "../../components/ProductItem";
import { addToCart } from "../../redux/cartSlice";
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import CustomHeaderButton from "../../components/UI/HeaderButton";
const ProductsOverviewScreen = ({ navigation }) => {
const products = useSelector(state => state.products.availableProducts);
const dispatch = useDispatch();
useEffect(() => {
navigation.setOptions({
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Orders"
iconName={Platform.OS === 'android' ? 'md-menu' : 'ios-menu'}
onPress={() => navigation.toggleDrawer()}
/>
</HeaderButtons>
),
headerRight: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Cart"
iconName={Platform.OS === 'android' ? 'md-cart' : 'ios-cart'}
onPress={() => navigation.navigate('Cart')}
/>
</HeaderButtons>
)
});
}, [])
return(
<FlatList
data={products}
renderItem={({item}) =>
<ProductItem
image={item.imageUrl}
title={item.title}
price={item.price}
onViewDetail={() => { navigation.navigate('Product Details', { productId: item.id, productTitle: item.title })}}
onAddToCart={() => dispatch(addToCart(item))}
/>
}
/>
);
};
export default ProductsOverviewScreen;
编辑: 谢谢。我已经按照你说的做了(抽屉导航器中只有一个项目并将 OrdersScreen 移动到 StackNavigator。我也向抽屉添加了自定义内容。现在唯一不起作用的是当我打开抽屉时从 OrdersScreen(通过 Drawer Custom Content 访问),当我点击 'Products'(默认且唯一的 Drawer 项目)时,没有任何反应(抽屉隐藏但保留在 OrdersScreen 上)。这是更新的导航文件
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem, } from '@react-navigation/drawer';
import { Platform } from 'react-native';
import Colors from '../constants/Colors';
import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetailScreen from "../screens/shop/ProductDetailScreen";
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const CustomDrawerContent = (props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label="Orders" onPress={() => props.navigation.navigate('Orders')} />
</DrawerContentScrollView>
);
}
const AppNavigation = () => {
return(
<NavigationContainer>
<Drawer.Navigator initialRouteName="ShopNavigation" drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Products" component={ShopNavigation}/>
</Drawer.Navigator>
</NavigationContainer>
);
};
const ShopNavigation = () => {
return(
<Stack.Navigator>
<Stack.Screen
name="Products"
component={ProductsOverviewScreen}
options={{
title: 'All Products',
headerStyle: {
backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
},
headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
headerTitleStyle: {
fontFamily: 'open-sans-bold'
},
headerBackTitleStyle: {
fontFamily: 'open-sans'
}
}}
/>
<Stack.Screen name="Product Details" component={ProductDetailScreen} />
<Stack.Screen name="Cart" component={CartScreen} />
<Stack.Screen name="Orders" component={OrdersScreen} />
</Stack.Navigator>
);
};
export default AppNavigation;
编辑2:
所以现在我在 CustomDrawer 中有两个 DrawItems,它们在 'All Products' 和 'Orders' 中都可以正常工作。我遇到的问题是我无法摆脱默认的 DrawerNavigation 条目(不是自定义内容):
<Drawer.Screen name="ShopNavigation" component={ShopNavigation}/>
因为那意味着 Drawer.Navigator 没有任何 children。默认情况下,它必须默认为 StackNavigator,不是吗?您建议我应该让所有条目都来自 CustomDrawerContent。目前抽屉里有以下物品:
- ShopNavigation(默认,在 'Orders' 中点击时不起作用。)
- 所有产品(自定义内容,无处不在)
- 订单(自定义内容,无处不在)
const CustomDrawerContent = (props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label="All Products" onPress={() => props.navigation.navigate('All Products')} />
<DrawerItem label="Orders" onPress={() => props.navigation.navigate('Orders')} />
</DrawerContentScrollView>
);
}
const AppNavigation = () => {
return(
<NavigationContainer>
<Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="ShopNavigation" component={ShopNavigation}/>
</Drawer.Navigator>
</NavigationContainer>
);
};
const ShopNavigation = () => {
return(
<Stack.Navigator>
<Stack.Screen
name="All Products"
component={ProductsOverviewScreen}
options={{
title: 'All Products',
headerStyle: {
backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
},
headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
headerTitleStyle: {
fontFamily: 'open-sans-bold'
},
headerBackTitleStyle: {
fontFamily: 'open-sans'
}
}}
/>
<Stack.Screen name="Product Details" component={ProductDetailScreen} />
<Stack.Screen name="Cart" component={CartScreen} />
<Stack.Screen name="Orders" component={OrdersScreen} />
</Stack.Navigator>
);
};
发生这种情况是因为 header 被添加到堆栈导航器中的屏幕,而不是添加到作为抽屉导航器一部分的屏幕。如果您希望 header 显示在所有屏幕上,我建议您的抽屉导航器只有一个屏幕,它实际上是一个堆栈导航器,并且可以工作。在这种情况下,您还需要一个自定义抽屉组件来显示您想要的项目,因为默认情况下只有一个条目。
要控制 header 在抽屉导航器的不同屏幕中的可见性,您可以使用 screenOptions 来隐藏和显示 header 到特定的抽屉屏幕。
<Drawer.Navigator screenOptions={({route}) => ({
headerShown: route.name === "screen1" ?false : true
})}>
我的导航文件如下。所有注册到堆栈导航器的屏幕都有一个 header。使用抽屉导航器注册为第二个选项的一个屏幕根本没有 header (OrdersScreen)。我也尝试在 Stack 导航器下添加它的条目,但它没有改变任何东西。 OrderScreen 中的 setOptions 没有任何效果,因为没有显示 header。
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { Platform } from 'react-native';
import Colors from '../constants/Colors';
import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetailScreen from "../screens/shop/ProductDetailScreen";
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const AppNavigation = () => {
return(
<NavigationContainer>
<Drawer.Navigator initialRouteName="ShopNavigation">
<Drawer.Screen name="Products" component={ShopNavigation}/>
<Drawer.Screen name="Orders" component={OrdersScreen} />
</Drawer.Navigator>
</NavigationContainer>
);
};
const ShopNavigation = () => {
return(
<Stack.Navigator>
<Stack.Screen
name="Products"
component={ProductsOverviewScreen}
options={{
title: 'All Products',
headerStyle: {
backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
},
headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
headerTitleStyle: {
fontFamily: 'open-sans-bold'
},
headerBackTitleStyle: {
fontFamily: 'open-sans'
}
}}
/>
<Stack.Screen name="Product Details" component={ProductDetailScreen} />
<Stack.Screen name="Cart" component={CartScreen} />
</Stack.Navigator>
);
};
export default AppNavigation;
OrderScreen如下:
import React, {useEffect} from 'react';
import {FlatList, View, Platform, Text, Button} from 'react-native';
import { useSelector } from 'react-redux';
import {HeaderButtons, Item} from "react-navigation-header-buttons";
import CustomHeaderButton from "../../components/UI/HeaderButton";
const OrdersScreen = (props) => {
const orders = useSelector(state => state.orders.orders);
useEffect(() => {
props.navigation.setOptions({
title: 'Your Orders',
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Orders"
iconName={Platform.OS === 'android' ? 'md-menu' : 'ios-menu'}
onPress={() => props.navigation.toggleDrawer()}
/>
</HeaderButtons>
),
});
},[])
return(
<View>
<Text>Orders screens</Text>
<Text>some text</Text>
<Text>Yet another</Text>
<Button title="toggle Drawer" onPress={() => props.navigation.toggleDrawer()} />
</View>
);
};
export default OrdersScreen;
Stack 导航中的默认屏幕 ProductsOverviewScreen 与 header 按钮和 header 图标配合使用效果很好。
import React, { useEffect } from 'react';
import { FlatList, Platform } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import ProductItem from "../../components/ProductItem";
import { addToCart } from "../../redux/cartSlice";
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import CustomHeaderButton from "../../components/UI/HeaderButton";
const ProductsOverviewScreen = ({ navigation }) => {
const products = useSelector(state => state.products.availableProducts);
const dispatch = useDispatch();
useEffect(() => {
navigation.setOptions({
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Orders"
iconName={Platform.OS === 'android' ? 'md-menu' : 'ios-menu'}
onPress={() => navigation.toggleDrawer()}
/>
</HeaderButtons>
),
headerRight: () => (
<HeaderButtons HeaderButtonComponent={CustomHeaderButton}>
<Item
title="Cart"
iconName={Platform.OS === 'android' ? 'md-cart' : 'ios-cart'}
onPress={() => navigation.navigate('Cart')}
/>
</HeaderButtons>
)
});
}, [])
return(
<FlatList
data={products}
renderItem={({item}) =>
<ProductItem
image={item.imageUrl}
title={item.title}
price={item.price}
onViewDetail={() => { navigation.navigate('Product Details', { productId: item.id, productTitle: item.title })}}
onAddToCart={() => dispatch(addToCart(item))}
/>
}
/>
);
};
export default ProductsOverviewScreen;
编辑: 谢谢。我已经按照你说的做了(抽屉导航器中只有一个项目并将 OrdersScreen 移动到 StackNavigator。我也向抽屉添加了自定义内容。现在唯一不起作用的是当我打开抽屉时从 OrdersScreen(通过 Drawer Custom Content 访问),当我点击 'Products'(默认且唯一的 Drawer 项目)时,没有任何反应(抽屉隐藏但保留在 OrdersScreen 上)。这是更新的导航文件
import 'react-native-gesture-handler';
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem, } from '@react-navigation/drawer';
import { Platform } from 'react-native';
import Colors from '../constants/Colors';
import ProductsOverviewScreen from "../screens/shop/ProductsOverviewScreen";
import ProductDetailScreen from "../screens/shop/ProductDetailScreen";
import CartScreen from "../screens/shop/CartScreen";
import OrdersScreen from "../screens/shop/OrdersScreen";
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const CustomDrawerContent = (props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label="Orders" onPress={() => props.navigation.navigate('Orders')} />
</DrawerContentScrollView>
);
}
const AppNavigation = () => {
return(
<NavigationContainer>
<Drawer.Navigator initialRouteName="ShopNavigation" drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Products" component={ShopNavigation}/>
</Drawer.Navigator>
</NavigationContainer>
);
};
const ShopNavigation = () => {
return(
<Stack.Navigator>
<Stack.Screen
name="Products"
component={ProductsOverviewScreen}
options={{
title: 'All Products',
headerStyle: {
backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
},
headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
headerTitleStyle: {
fontFamily: 'open-sans-bold'
},
headerBackTitleStyle: {
fontFamily: 'open-sans'
}
}}
/>
<Stack.Screen name="Product Details" component={ProductDetailScreen} />
<Stack.Screen name="Cart" component={CartScreen} />
<Stack.Screen name="Orders" component={OrdersScreen} />
</Stack.Navigator>
);
};
export default AppNavigation;
编辑2: 所以现在我在 CustomDrawer 中有两个 DrawItems,它们在 'All Products' 和 'Orders' 中都可以正常工作。我遇到的问题是我无法摆脱默认的 DrawerNavigation 条目(不是自定义内容):
<Drawer.Screen name="ShopNavigation" component={ShopNavigation}/>
因为那意味着 Drawer.Navigator 没有任何 children。默认情况下,它必须默认为 StackNavigator,不是吗?您建议我应该让所有条目都来自 CustomDrawerContent。目前抽屉里有以下物品:
- ShopNavigation(默认,在 'Orders' 中点击时不起作用。)
- 所有产品(自定义内容,无处不在)
- 订单(自定义内容,无处不在)
const CustomDrawerContent = (props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label="All Products" onPress={() => props.navigation.navigate('All Products')} />
<DrawerItem label="Orders" onPress={() => props.navigation.navigate('Orders')} />
</DrawerContentScrollView>
);
}
const AppNavigation = () => {
return(
<NavigationContainer>
<Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="ShopNavigation" component={ShopNavigation}/>
</Drawer.Navigator>
</NavigationContainer>
);
};
const ShopNavigation = () => {
return(
<Stack.Navigator>
<Stack.Screen
name="All Products"
component={ProductsOverviewScreen}
options={{
title: 'All Products',
headerStyle: {
backgroundColor: Platform.OS === 'android' ? Colors.primary : ''
},
headerTintColor: Platform.OS === 'android' ? 'white' : Colors.primary,
headerTitleStyle: {
fontFamily: 'open-sans-bold'
},
headerBackTitleStyle: {
fontFamily: 'open-sans'
}
}}
/>
<Stack.Screen name="Product Details" component={ProductDetailScreen} />
<Stack.Screen name="Cart" component={CartScreen} />
<Stack.Screen name="Orders" component={OrdersScreen} />
</Stack.Navigator>
);
};
发生这种情况是因为 header 被添加到堆栈导航器中的屏幕,而不是添加到作为抽屉导航器一部分的屏幕。如果您希望 header 显示在所有屏幕上,我建议您的抽屉导航器只有一个屏幕,它实际上是一个堆栈导航器,并且可以工作。在这种情况下,您还需要一个自定义抽屉组件来显示您想要的项目,因为默认情况下只有一个条目。
要控制 header 在抽屉导航器的不同屏幕中的可见性,您可以使用 screenOptions 来隐藏和显示 header 到特定的抽屉屏幕。
<Drawer.Navigator screenOptions={({route}) => ({
headerShown: route.name === "screen1" ?false : true
})}>