I created a drawer with screens but wanted to add also an image of the user at the top of the drawer. I used in the Drawer.Navigator the drawerContent option and used a custom function and called it. The problem is that the image is set on the bottom and not in the top. I've tried searching in the web but I didn't find a way to set it on top. Here is the code:
const Drawer = createDrawerNavigator()
const CustomDrawerContent=(props) =>{
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem
icon={({color})=> <Image style={{ width: 90, height: 90, borderRadius: 400 / 2 }} source={{ uri: auth.currentUser.photoURL }}></Image>}
label=""
/>
</DrawerContentScrollView>
);
}
const DrawerNavigator = () => {
return (
<Drawer.Navigator initialRouteName='TabNavigator' drawerContent={CustomDrawerContent}>
<Drawer.Screen name='Início' component={TabNavigator}/>[enter image description here][1]
<Drawer.Screen name="Lista de Espera" component={PermissionsStackScreen} />
<Drawer.Screen name="Comunidade" component={CommunityStackScreen} />
<Drawer.Screen name='Análises em Espera' component={AwaitingStackScreen}/>
<Drawer.Screen name='Confirmar Análises' component={VerifyStackScreen}/>
<Drawer.Screen name='Análises Rejeitadas' component={RejectedStackScreen}/>
<Drawer.Screen name='Gerir Reagentes' component={ReagentStackScreen}/>
<Drawer.Screen name='Gerir Equipamentos' component={EquipmentStackScreen}/>
</Drawer.Navigator>
);
}
export default DrawerNavigator
I have also added the link of the how the code looks like.
[1]: https://i.stack.imgur.com/9b9f5.jpg
Any help would be useful!
Just simply change the order of the component here :
const CustomDrawerContent=(props) =>{
return (
<DrawerContentScrollView {...props}>
{/* Render image item first */}
<DrawerItem
icon={({color})=> <Image style={{ width: 90, height: 90, borderRadius: 400 / 2 }} source={{ uri: auth.currentUser.photoURL }}></Image>}
label=""
/>
{/* then render others menu item */}
<DrawerItemList {...props} />
</DrawerContentScrollView>
);
}
Related
I new in react-native and junior developer.
I'm using react-native v0.70.6
#react-navigation/stack and #react-navigation/bottom-tabs.
My tab bottom component looks like this:
<Tab.Navigator
initialRouteName='Home'
screenOptions={{
headerShown:false,
tabBarShowLabel:false,
tabBarStyle:style.tabsBottomContainer
}}
sceneContainerStyle={style.backgroundContent}
>
<Tab.Screen
name='Assets'
component={AssetScreen}
options={{unmountOnBlur:true,tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconAsset}
style={{
tintColor: focused ? '#00B2DF' : '',
marginTop: 8
}}
/>
</View>
)}}
/>
<Tab.Screen
name='Bluetooth'
component={ConnectScreen}
children = {()=> <NotFoundGateway />}
options={{unmountOnBlur:true,tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconBluetooth}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)}}
/>
<Tab.Screen
name='Home'
component={HomeScreen}
options={{unmountOnBlur:true,tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconHome}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)}}
/>
</Tab.Navigator>
Inside index.tsx I have a navigation that does not need the bottom tabs. For example the Login. -->
<NavigationContainer>
<Stack.Navigator initialRouteName='tabsBottomHome'>
{state.isSignIn ? (
<>
<Stack.Screen
name='tabsBottomHome'
component={TabsBottomHome}
options={headerOptions}
/>
):(
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="LoginError"
component={LoginError}
options={headerOptions}
/>
)
</>
)}
</Stack.Navigator>
</NavigationContainer>
The components between the bottom tabs are displayed perfectly. But since I add secondary components to my navigation. For example, I enter the Bluetooth component, within that component I have to enter another component, without losing the bottom tabs.
What would be the correct way to do it?
And how could I set all the routes inside my tabs bottom component?
Solved!
I had to change my navigation structure as follows :
my main structure is like this-->
<NavigationContainer>
<Stack.Navigator initialRouteName='tabsBottomHome'
screenOptions={{
headerTitle: () => <Header />,
headerBackground: () => <HeaderBackground />,
headerLeft: ({ onPress, canGoBack }) =>
canGoBack ? (
<Pressable onPress={onPress} style={{ width: 30, height: 15 }}>
<ArrowLeft height={15} width={15} style={{ marginLeft: 15 }} />
</Pressable>
) : (
<Pressable style={{ width: 65, height: 35 }}></Pressable>
),
headerRight: () => <HeaderRight />,
}}
>
{state.isSignIn ? (
<>
<Stack.Screen
name='tabsBottomHome'
component={TabsBottomHome}
options={{headerShown: false }}
/>
</>
) : (
<>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="LoginError"
component={LoginError}
/>
</>
)}
</Stack.Navigator>
</NavigationContainer>
my tab bottom navigation structure looks like this
<Tab.Navigator
initialRouteName='Home'
screenOptions={{
headerShown:true,
tabBarShowLabel:false,
tabBarStyle:style.tabsBottomContainer,
unmountOnBlur: true,
headerTitle: () => <Header />,
headerBackground: () => <HeaderBackground />,
headerLeft: () =>
routeName != "Home" ? (
<Pressable onPress={navigateBack} style={{ width: 65, height: 15 }}>
<ArrowLeft height={15} width={15} style={{ marginLeft: 15 }} />
</Pressable>
)
: (
<Pressable style={{ width: 65, height: 35 }}></Pressable>
)
,
headerRight: () => <HeaderRight />,
}}
sceneContainerStyle={style.backgroundContent}
screenListeners={({route})=>({
state: ()=> {
setRouteName(route.name);
}
})}
backBehavior={'history'}
>
<Tab.Screen
name='Assets'
component={AssetScreen}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconAsset}
style={{
tintColor: focused ? '#00B2DF' : '',
marginTop: 8
}}
/>
</View>
)}} />
<Tab.Screen
name='GatewayStack'
component={ConnectGatewayStack}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconBluetooth}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)}} />
</Tab.Navigator>
And my ConnectGatawayStack structure contains the navigation of all that Tab, therefore it is inside my Tab and the focus is not lost and it works correctly. Obviously now I am facing a goBack problem. but that's another kind of problem.
ConnectGatawayStack -->
export type StackConnectList = {
Connect: undefined;
QRScan: undefined;
GatewayList: undefined;
GatewayInfo: undefined;
NotFoundGateway: undefined;
GatewayDetected: undefined;
ErrorConnecting: undefined;
}
const GatewayStack = createStackNavigator<StackConnectList>();
const ConnectGatewayStack = () =>{
return (
<GatewayStack.Navigator initialRouteName='Connect'
screenOptions={{headerShown:false}}
>
<GatewayStack.Screen name='Connect' component={ConnectScreen} />
<GatewayStack.Screen name='GatewayList' component={GatewayList} />
<GatewayStack.Screen name='GatewayInfo' component={GatewayInfo} />
<GatewayStack.Screen name='QRScan' component={QRScanScreen} />
<GatewayStack.Screen name='NotFoundGateway' component={NotFoundGateway} />
<GatewayStack.Screen name='GatewayDetected' component={GatewayDetected} />
<GatewayStack.Screen name='ErrorConnecting' component={ErrorConnecting} />
</GatewayStack.Navigator>
)
}
export {ConnectGatewayStack};
Thanks!
I have this problem several days ago and I can't find a solution.
This is my navigation structure
Index.tsx -->
<NavigationContainer>
<Stack.Navigator initialRouteName='tabsBottomHome'
screenOptions={{
headerTitle: () => <Header />,
headerBackground: () => <HeaderBackground />,
headerLeft: ({ onPress, canGoBack }) =>
canGoBack ? (
<Pressable onPress={onPress} style={{ width: 30, height: 15 }}>
<ArrowLeft height={15} width={15} style={{ marginLeft: 15 }} />
</Pressable>
) : (
<Pressable style={{ width: 65, height: 35 }}></Pressable>
),
headerRight: () => <HeaderRight />,
}}
>
{state.isSignIn ? (
<>
<Stack.Screen
name='tabsBottomHome'
component={TabsBottomHome}
options={{headerShown: false }}
/>
</>
) : (
<>
<Stack.Screen
name="Login"
component={LoginScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="LoginError"
component={LoginError}
/>
</>
)}
</Stack.Navigator>
</NavigationContainer>
This would be the first navigation of my application. So far everything is going well.
TabsBottomNavigation -->
<Tab.Navigator
initialRouteName='Home'
screenOptions={{
headerShown:true,
tabBarShowLabel:false,
tabBarStyle:style.tabsBottomContainer,
unmountOnBlur: true,
headerTitle: () => <Header />,
headerBackground: () => <HeaderBackground />,
headerLeft: () =>
routeName != "Home" ? (
<Pressable onPress={navigateBack} style={{ width: 65, height: 15 }}>
<ArrowLeft height={15} width={15} style={{ marginLeft: 15 }} />
</Pressable>
)
: (
<Pressable style={{ width: 65, height: 35 }}></Pressable>
)
,
headerRight: () => <HeaderRight />,
}}
sceneContainerStyle={style.backgroundContent}
screenListeners={({route})=>({
state: ()=> {
setRouteName(route.name);
}
})}
backBehavior={'history'}
>
<Tab.Screen
name='Assets'
component={AssetScreen}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconAsset}
style={{
tintColor: focused ? '#00B2DF' : '',
marginTop: 8
}}
/>
</View>
)}} />
<Tab.Screen
name='GatewayStack'
component={ConnectGatewayStack}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconBluetooth}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)}} />
<Tab.Screen
name='Home'
component={HomeScreen}
options={{tabBarIcon:({focused,color})=>(
<View>
<Image
source={iconHome}
style={{
tintColor: focused ? '#00B2DF' : ''
}}
/>
</View>
)
}} />
</Tab.Navigator>
everything is fine here too, the conflict is in the ConnectGatewayStack stack
ConnectGatewayStack -->
export type StackConnectList = {
Connect: undefined;
QRScan: undefined;
GatewayList: undefined;
GatewayInfo: undefined;
NotFoundGateway: undefined;
GatewayDetected: undefined;
ErrorConnecting: undefined;
}
const GatewayStack = createStackNavigator<StackConnectList>();
const ConnectGatewayStack = () =>{
return (
<GatewayStack.Navigator initialRouteName='Connect'
screenOptions={{headerShown:false}}
>
<GatewayStack.Screen name='Connect' component={ConnectScreen} />
<GatewayStack.Screen name='GatewayList' component={GatewayList} />
<GatewayStack.Screen name='GatewayInfo' component={GatewayInfo} />
<GatewayStack.Screen name='QRScan' component={QRScanScreen} />
<GatewayStack.Screen name='NotFoundGateway' component={NotFoundGateway} />
<GatewayStack.Screen name='GatewayDetected' component={GatewayDetected} />
<GatewayStack.Screen name='ErrorConnecting' component={ErrorConnecting} />
</GatewayStack.Navigator>
)
}
export {ConnectGatewayStack};
When I navigate to the ConnectGatewayStack tab, which contains the other components that I just showed, if I go to a child component and press the back button in header, it returns directly to the TabsBottomHome (that is, to the Tabs navigation) and not to the component that was previously visited.
For the navigation back, i use
import { useNavigation } from '#react-navigation/core';
whit
const navigation = useNavigation();
navigation.goback();
I tried whit diferents methods, but none solved my problem.
example test whit
backBehavior={'history'}
backBehavior={'order'}
and many functions of the core react-native and react-native-navigation
any ideas?
sorry for my bad english and thank you very much
I faced a strange problem that happened only on a small screen, I tested on 480x800 4 inches and 2400x1080 6.6inches screen, and that happened on the smaller one (480x800), the drawer flashes on any window that contains a text input after the keyboard closes.
Just for understanding better the problem there's a video
#react-navigation/drawer#6.1.8
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItem,
} from '#react-navigation/drawer'
const Drawer = createDrawerNavigator()
<Drawer.Navigator
detachInactiveScreens={false}
useLegacyImplementation={false}
initialRouteName="Home"
drawerContent={(props) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItem
icon={() => {
return (
<Ionicons
light
name="arrow-back-outline"
size={20}
color="black"
/>
)
}}
label="Menu"
onPress={() =>
props.navigation.dispatch(DrawerActions.closeDrawer())
}
/>
<View
style={{
borderBottomColor: '#999999',
borderBottomWidth: 0.5,
}}
/>
</DrawerContentScrollView>
)
}}
screenOptions={() => {
return {
swipeEnabled: true,
headerShown: false,
}
}}
>
<Drawer.Screen name="Home" component={Home} />
</Drawer.Navigator>
I am working on accessibility labels for the voice assistant, I've done most of the tags but I can not set the bottom tab navigator options, how can I use accessibility labels with the below BottomTab.Navigator components?
In the below, I could set the labels with the Icons but it is encapslating limited area.
When I try with Bottom.Navigator, throwing errors something like that:
Error: A navigator can only contain 'Screen' components as its direct children (found 'undefined'). To render this component in the navigator, pass it in the 'component' prop to 'Screen'.
export default function BottomTabNavigator(): any {
const colorScheme = useColorScheme();
return (
<BottomTab.Navigator
initialRouteName={Routes.TAB_ONE}
tabBarOptions={{
showLabel: false,
inactiveBackgroundColor: Colors[colorScheme].secondaryColor,
activeBackgroundColor: Colors[colorScheme].secondaryColor,
style: {
borderTopWidth: 0,
borderTopColor: 'transparent',
height: 50,
},
}}
>
<BottomTab.Screen
name={Routes.TAB_ONE}
component={TabOneNavigator}
options={{
tabBarIcon: () => (
<View accessible={true} accessibilityLabel="home page">
<CustomIcon name="home" color={Colors[colorScheme].buttonText} />
</View>
),
}}
/>
<BottomTab.Screen
name={Routes.TAB_TWO}
component={TabTwoNavigator}
options={{
tabBarIcon: () => (
<View accessible={true} accessibilityLabel="downloads">
<CustomIcon
name="library"
color={Colors[colorScheme].buttonText}
/>
</View>
),
}}
/>
<BottomTab.Screen
name={Routes.TAB_THREE}
component={TabThreeNavigator}
options={{
tabBarIcon: () => (
<View accessible={true} accessibilityLabel="menu">
<CustomIcon name="menu" color={Colors[colorScheme].buttonText} />
</View>
),
}}
/>
</BottomTab.Navigator>
);
}
Thanks in advance
I have a drawer navigation, what I wanted to happen is add divider separating the drawer icon and texts, but I get an error instead
Error is: A navigator can only contain screen components...
Here is my approach:
function DrawerNav(): React$Element<{}> {
return (
<Drawer.Navigator
drawerStyle={styles.drawerStyle}
drawerContentOptions={{
activeTintColor: 'white',
inactiveTintColor: 'white',
activeBackgroundColor: '#163E69',
inactiveBackgroundColor: '#02152B'
}}>
<Drawer.Screen
name="Dashboard"
component={Dashboard}
options={{
drawerIcon: () => (
<Image source = {"assets/icons/dashboard.png"} />
),
}}
/>
<DrawerDivider label="Account" /> // This is my divider component
<Drawer.Screen
name="Profile"
component={Profile}
options={{
drawerIcon: () => (
<Image source={'assets/icons/profile.png'} />
),
}}
/>
<DrawerDivider label="Actions" /> // also my divider component
<Drawer.Screen
name="Settings"
component={Settings}
options={{
drawerIcon: () => (
<Image source={'assets/icons/settings.png'} />
),
}}
/>
<DrawerDivider label="Actions" /> // also my divider component
<Drawer.Screen
name="Logout"
component={Logout}
options={{
drawerIcon: () => (
<Image source={'assets/icons/logout.png'} />
),
}}
/>
</Drawer.Navigator>
);
}
Any suggestions/help are appreciated.
this how I implemented it in my project , you need to create a custom drawerContent component , drawerContent gives incredible amount of flexibility you can literally create what ever you want with it .
Navigator :
import DrawerContent from './DrawerContent'
import { createDrawerNavigator } from '#react-navigation/drawer';
const Navigator =({authenticated,userType})=>{
const Drawer = createDrawerNavigator();
return <Drawer.Navigator
screenOptions={{headerShown:false}}
initialRouteName="INTIALROUTE"
drawerContent={props => <DrawerContent {...props} />}
>
<Drawer.Screen name="route1" component={Screen1} />
<Drawer.Screen name="route1" component={Screen2} />
</Drawer.Navigator>
}
the custom drawerContent component :
import React from 'react'
import {StyleSheet,View,Text,TouchableOpacity} from 'react-native'
import {DrawerContentScrollView,DrawerItem} from '#react-navigation/drawer';
const DrawerContent=(props)=> {
const {navigation}=props
const naviagetToRoute=(e)=>{
navigation.navigate(route)
}
//here you can return diffrent drawerContent based on auth state for example
if(isAuthenticated){
//isAuthenticated can be passed through props using redux's connect or context api
return <View style={{flex:1}}>
<DrawerContentScrollView {...props}>
<TouchableOpacity onPress={naviagetToRoute}>
<View style={styles.drawerItem}>
<Image source = {"assets/icons/logout.png"} />
<Text style={{color:colors.BLACK}} >Logout</Text>
</View>
</TouchableOpacity>
</DrawerContentScrollView>
</View>
}
return (
<View style={{flex:1}}>
<DrawerContentScrollView {...props}>
<TouchableOpacity onPress={naviagetToRoute}>
<View style={styles.drawerItem}>
<Image source = {"assets/icons/dashboard.png"} />
<Text style={{color:colors.BLACK}} >DashBoard</Text>
</View>
</TouchableOpacity>
</DrawerContentScrollView>
</View>
)
}
export default DrawerContent
const styles = StyleSheet.create({
drawerItem: {
display :'flex',
flexDirection:'row',
alignItems:'center',
justifyContent:"space-between",
padding:16,
elevation:12,
backgroundColor:'#fff',
borderRadius:12,
marginBottom:16,
flex:1
}
});