How to add multiple divider component in a react navigation drawer - reactjs

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

Related

React Native Nested Stack Inside BottomTabNavigator issue

The navigation process I want to achieve is (BottomTabNavigator -> RoutinesStackNavigator -> Routines) which I'm using a stack navigator nested inside a bottom tab navigator
When I navigate to the RoutinesStackNavigator it isn't loading the Routines page and I am not sure why.
BottomTabNavigation.tsx
export default function Navigation() {
return (
<>
<SoundProvider>
<TimerProvider>
<NavigationContainer>
<Tab.Navigator
sceneContainerStyle={{ backgroundColor: COLORS.white }}
initialRouteName="Pomodoro"
screenOptions={({ route, navigation }) => ({
tabBarShowLabel: false,
headerShown: false,
tabBarStyle: [styles.tabBar, styles.tabBarBoxShadow],
tabBarIcon: ({ focused }) => {
let rn = route.name;
let iconTag;
// assigning navigation icon based on name of route
if (rn === pomodoroName) {
// assigning JSX Tag
iconTag = (
<PomodoroIcon
size={iconSize}
fillColor={iconColor}
isFocused={focused}
/>
);
} else if (rn === agendaName) {
iconTag = (
<AgendaIcon
size={iconSize}
fillColor={iconColor}
isFocused={focused}
/>
);
} else if (rn === tutorialsName) {
iconTag = (
<TutorialsIcon
size={iconSize}
fillColor={iconColor}
isFocused={focused}
/>
);
} else if (rn === routinesStackNavigatorName) {
iconTag = (
<RoutinesIcon
size={iconSize}
fillColor={iconColor}
isFocused={focused}
/>
);
}
return (
<Pressable
onPress={() => {
// add haptic feedback and navigate to new route
addLightHapticFeedback("light");
navigation.navigate(rn);
}}
>
{iconTag}
</Pressable>
);
},
})}
>
<Tab.Screen name={pomodoroName} component={Pomodoro} />
<Tab.Screen name={agendaName} component={Agenda} />
<Tab.Screen name={tutorialsName} component={Tutorials} />
<Tab.Screen
name={routinesStackNavigatorName}
component={RoutinesStackNavigator}
/>
</Tab.Navigator>
</NavigationContainer>
</TimerProvider>
</SoundProvider>
</>
);
}
RoutinesStackNavigator.tsx
export default function RoutinesStackNavigator() {
const Stack = createStackNavigator();
return (
<>
<SafeAreaView>
<Stack.Navigator initialRouteName="Routines">
<Stack.Screen name="Routines" component={Routines} />
<Stack.Screen name="CreateRoutine" component={CreateRoutine} />
</Stack.Navigator>
</SafeAreaView>
</>
);
}
index.Routines.tsx
export default function Routines() {
const { width } = useWindowDimensions();
return (
<>
<FocusedStatusBar barStyle="light-content" />
<View style={styles.container}>
<View style={styles.row}>
<Text style={styles.title}>{STRINGS.routinesTitle}</Text>
<TouchableOpacity onPress={() => {}}>
<AntDesign name="pluscircle" size={44} color={COLORS.white} />
</TouchableOpacity>
</View>
<View style={[styles.main, { width: width }]}>
<View style={{ height: "72%" }}>
<ScrollView
showsVerticalScrollIndicator={true}
style={{ marginTop: 10, marginBottom: 10 }}
>
<RoutineCard />
<RoutineCard />
</ScrollView>
</View>
<TouchableOpacity style={styles.button} onPress={() => {}}>
<Text style={styles.buttonText}>Start Session</Text>
</TouchableOpacity>
</View>
</View>
</>
);
}
none of the Routines component renders, except the StatusBar color changes. So the component must be rendering but the rest of the content doesn't show up.
You have to remove <SafeAreaView> from RoutinesStackNavigator.tsx
const Stack = createStackNavigator();
export default function RoutinesStackNavigator() {
return (
<Stack.Navigator initialRouteName="Routines">
<Stack.Screen name="Routines" component={Routines} />
<Stack.Screen name="CreateRoutine" component={CreateRoutine} />
</Stack.Navigator>
);
}

How to set DrawerItem on top of Drawer Screens

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

need to display the header in all screen on react native navigation V5

i have the following header.js
import React from 'react';
import {View, Text, StyleSheet, Image} from 'react-native';
import {MaterialCommunityIcons} from '#expo/vector-icons';
export default function header({navigation}, title) {
const openMenu =() => {
navigation.openDrawer()
}
return (
<View style={styles.header}>
<MaterialCommunityIcons name='menu'
size={24} color='black'
onPress={openMenu}
style={styles.icon}
/>
<View style={styles.headerTitle}>
<Image style={styles.logo} source={require('../assets/oau-ico-hat.png')}/>
<Text style={styles.headerText}>title={title}</Text>
{/* */}
</View>
</View>
)
}
const styles = StyleSheet.create({
header:{
width:'100%',
height: '100%',
flexDirection:'row',
alignItems:'center',
justifyContent:'center',
},
headerText:{
fontWeight: 'bold',
fontSize: 20,
color: '#333',
letterSpacing: 1,
marginTop:8,
marginHorizontal: 50,
marginLeft:10,
},
logo: {
width: 40,
height: 40,
},
icon:{
position:'absolute',
left: 0.7,
},
headerTitle:{
flexDirection:'row',
},
})
then i had the following App.js
const Drawer = createDrawerNavigator();
const DrawerNavigator=() => {
return (
<Drawer.Navigator
drawerContent={props => <DrawerContent {...props}
/>}
>
<Drawer.Screen name="Home" component={StackNavigator}
/>
<Drawer.Screen name="Faculties" component={Faculty}
/>
</Drawer.Navigator>
)
}
const Tab = createBottomTabNavigator();
const TabNavigator = ({navigation}) => (
<Tab.Navigator
screenOptions={{
headerStyle:{backgroundColor: "tomato" , elevation:0},
headerTintColor:"#fff",
headerTitleAlign:'center',
headerTitle: () => <Header navigation={navigation} title='O.A.U'/>
}}>
<Tab.Screen name="Home" component={DrawerNavigator} />
<Tab.Screen name="Faculties" component={Faculty}
/>
</Tab.Navigator>
)
const Stack = createStackNavigator();
const StackNavigator = ({navigation}) => (
<Stack.Navigator
screenOptions={{
headerStyle:{backgroundColor: "tomato" , elevation:0},
headerTintColor:"#fff",
headerTitleAlign:'center',
headerTitle: () => <Header navigation={navigation} title='O.A.U'/>
}}
>
<Stack.Screen name="Home" component={Home}
options={() => {<Header navigation={navigation} title='O.A.U'/>}}
/>
<Stack.Screen name="TabsBottom" component={Faculty}
/>
</Stack.Navigator>
);
const styles = StyleSheet.create({
header:{
alignItems:'center',
},
})
export default function App() {
return (
<NavigationContainer>
<TabNavigator/>
</NavigationContainer>
);
}
I have homeStack.js where in React Navigation V4 it was working as follow:any idea how can i make that work in V% react-navigation
import React from 'react';
import {createStackNavigator} from '#react-navigation/stack';
import Header from '../shared/header';
import Home from '../screens/homeScreen';
import Faculty from '../screens/faculties'
const screens ={
Home: {
screen: Home,
screenOptions:({ navigation } )=> {
return {
headerTitle: () => <Header navigation={navigation} title='O.A.U'/>,
}
}
},
Faculty: {
screen: Faculty,
navigatioptions:({ navigation } )=> {
return {
headerTitle: () => <Header navigation={navigation} title='O.A.U'/>,
}
}
}
}
const HomeStack = createStackNavigator();
export default HomeStack;
i have a drwer.js for the drawer meny as follow:
import React from "react";
import { StyleSheet, View } from "react-native";
import {
DrawerContentScrollView,
DrawerItem,
DrawerItemList,
} from "#react-navigation/drawer";
import {
Avatar,
Title,
Caption,
Paragraph,
Drawer,
Text,
TouchableRipple,
Switch,
} from "react-native-paper";
import { MaterialCommunityIcons, FontAwesome5 } from "#expo/vector-icons";
import Home from './homeStack'
export function DrawerContent({ ...props }) {
return (
<View style={{ flex: 1 }}>
<DrawerContentScrollView {...props}>
{/* <DrawerItemList {...props}/> */}
<DrawerItem
icon={({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
)}
label="Home"
onPress={() => props.navigation.navigate("Home")}
/>
<DrawerItem
icon={({ color, size }) => (
<FontAwesome5 name="university" color={color} size={size} />
)}
label="Faculties"
onPress={() => props.navigation.navigate("Faculties")}
/>
</DrawerContentScrollView>
</View>
);
}
my questions as follow:
1.how can i display the header in all screen as the header will include the menu burger that pulls the drawer menu?
2. when clicking on Faculties menu from tab the drawer menu is not working unless i click on home menu from tab navigation, is my nested navigation correct or where am I going wrong?
P/S: please note this my first time on developing mobile app using react.
you can have a look at github and see if you can help from there # https://github.com/sudani/Uni_app.git
after spending the last 2 days looking for answer i found great youtube tutorial, i frogot about rules posting link but here what i have managed to do:
removed all the stack screens, tab screens to separate file then import the file into App.js:
the file as follow:
import React from 'react';
import {createStackNavigator} from '#react-navigation/stack';
import { createMaterialBottomTabNavigator } from '#react-navigation/material-bottom-tabs';
import Icon from 'react-native-vector-icons/Ionicons';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import HomeScreen from './homeScreen'
import FacultyScreen from './faculties';
const HomeStack = createStackNavigator();
const FacultyStack = createStackNavigator();
const Tab = createMaterialBottomTabNavigator();
const MainTabScreen =() => (
<Tab.Navigator
initialRouteName="Home"
activeColor="#fff"
barStyle={{ backgroundColor: 'tomato' }}
>
<Tab.Screen
name="Home"
component={HomeStackScreen}
options={{
tabBarLabel: 'Home',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="home" color={color} size={26} />
),
}}
/>
<Tab.Screen
name="Faculty"
component={FacultyStackScreen}
options={{
tabBarLabel: 'Updates',
tabBarIcon: ({ color }) => (
<MaterialCommunityIcons name="bell" color={color} size={26} />
),
}}
/>
</Tab.Navigator>
)
export default MainTabScreen;
const HomeStackScreen =({navigation}) => (
<HomeStack.Navigator
screenOptions={{
headerStyle: { backgroundColor: "tomato", elevation: 0 },
headerTintColor: "#fff",
headerTitleAlign: "center",
headerShown:true,
}}
>
<HomeStack.Screen name= "Home" component={HomeScreen}
options={{
title:'Overview',
headerLeft: () => (
<Icon.Button name="ios-menu" size={26}
backgroundColor="tomato" onPress={() => navigation.openDrawer() }></Icon.Button>
)
}}
/>
</HomeStack.Navigator>
)
const FacultyStackScreen =({navigation}) => (
<FacultyStack.Navigator
screenOptions={{
headerStyle: { backgroundColor: "tomato", elevation: 0 },
headerTintColor: "#fff",
headerTitleAlign: "center",
headerShown:true,
}}
>
<FacultyStack.Screen name= "Faculty" component={FacultyScreen}
options={{
headerLeft: () => (
<Icon.Button name="ios-menu" size={26}
backgroundColor="tomato" onPress={() => navigation.openDrawer() }></Icon.Button>
)
}}
/>
</FacultyStack.Navigator>
)
then the App.js as follow:
import React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import {createDrawerNavigator} from '#react-navigation/drawer';
import MainTabScreen from './app/screens/MaintabScreen';
import { DrawerContent } from "./app/routes/drawer";
const Drawer = createDrawerNavigator();
export default function App() {
return (
<NavigationContainer initialRouteName= "Home">
<Drawer.Navigator drawerContent={(props) => <DrawerContent {...props} />}>
<Drawer.Screen name="Home" component={MainTabScreen}/>
{/* <Drawer.Screen name="Faculty" component={FacultyStackScreen}/> */}
</Drawer.Navigator>
</NavigationContainer>
);
}
the drawer helper stayed the same as before
import React from "react";
import { StyleSheet, View } from "react-native";
import {
DrawerContentScrollView,
DrawerItem,
DrawerItemList,
} from "#react-navigation/drawer";
import {
Avatar,
Title,
Caption,
Paragraph,
Drawer,
Text,
TouchableRipple,
Switch,
} from "react-native-paper";
import { MaterialCommunityIcons, FontAwesome5 } from "#expo/vector-icons";
import Home from './homeStack'
export function DrawerContent({ ...props }) {
return (
<View style={{ flex: 1 }}>
<DrawerContentScrollView {...props}>
{/* <DrawerItemList {...props}/> */}
<DrawerItem
icon={({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={size} />
)}
label="Home"
onPress={() => props.navigation.navigate("Home")}
/>
<DrawerItem
icon={({ color, size }) => (
<FontAwesome5 name="university" color={color} size={size} />
)}
label="Faculties"
onPress={() => props.navigation.navigate("Faculty")}
/>
</DrawerContentScrollView>
</View>
);
}
I found this an Easy way of managing the nested navigation and it is almost what i wanted if anyone has better improvement suggestion that will be great

TypeError: Cannot read property 'navigate' of undefined react native drawer

I am trying to make drawer navigation from component. But all time its giving me error "TypeError: Cannot read property 'navigate' of undefined" when click on menu ->profile link. Please suggest where I am wrong.
component/MenuPage.js
import React from 'react';
import {SafeAreaView, View, StyleSheet, Image, Text, Linking,} from 'react-native';
import { DrawerContentScrollView, DrawerItemList, DrawerItem,} from '#react-navigation/drawer';
const image = { uri: "" };
const CustomSidebarMenu = (props) => {
return (
<SafeAreaView style={[styles.LandingBodyColor, {flex: 1, paddingHorizontal:10}]}>
<View style={[styles.LandingMain, {marginVertical:10,}]}>
<Image source={image} style={{width:100, height:100, borderRadius:100,}} />
</View>
<View>
<Text style={[styles.TextCenter, {fontSize:18, color: '#fff', paddingBottom:10,}]}>Welcome Back.</Text>
</View>
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<View style={[styles.customItem]}>
<Text style={{marginRight:10,}}>
<FontAwesome name="user" style={[styles.MenuIcon, styles.VectorIconWhiteColor]}/>
</Text>
<Text style={[styles.WhiteColor]} onPress={() => navigation.navigate(Profile) >My Profile</Text>
</View>
</DrawerContentScrollView>
</SafeAreaView>
);
};
export default CustomSidebarMenu;
App.js
export default function App() {
return (
<NavigationContainer>
<Drawer.Navigator
drawerContentOptions={{
activeBackgroundColor: '#e40046',
}}
drawerContent={(props) => <CustomSidebarMenu {...props} />}
screenOptions={{
headerShown: false,
}}
>
<Drawer.Screen name="Landing Page" component={AllScreenStack}
options={() => ({
drawerLabel: () => null,
title: undefined,
drawerIcon: () => null,
headerTitleStyle: {
backgroundColor:'red',
},
})}
/>
</Drawer.Navigator>
</NavigationContainer>
);
}
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
Try with props like this
props.navigation.navigate('Profile')

How to space around top tab bar in react native?

I am working on a dummy project for practice using react navigation material top tab. Everything is working fine, I just want to know is there any way to space around the tabs? I attached the output image of my code
Here is my code
import * as React from "react";
import { createDrawerNavigator } from "#react-navigation/drawer";
import AccountsScreen from "../screens/AccountsScreen";
import FavouritesScreen from "../screens/FavouritesScreen";
import HomeScreen from "../screens/HomeScreen";
import SettingsScreen from "../screens/SettingsScreen";
import TrendsScreen from "../screens/TrendsScreen";
import { createMaterialTopTabNavigator } from "#react-navigation/material-top-tabs";
import { Dimensions } from "react-native";
import Income from "../screens/Income";
import Expense from "../screens/Expense";
const Drawer = createDrawerNavigator();
const Tab = createMaterialTopTabNavigator();
CategoriesTabScreens = () => {
return (
<Tab.Navigator
initialRouteName="Income"
tabBarOptions={{
indicatorStyle: {
height: Dimensions.get("window").height,
backgroundColor: "#29416F",
},
activeTintColor: "#fff",
inactiveTintColor: "#333",
}}
>
<Tab.Screen name="Income" component={Income} />
<Tab.Screen name="Expense" component={Expense} />
</Tab.Navigator>
);
};
const AppDrawer = () => {
return (
<Drawer.Navigator
initialRouteName="Home"
screenOptions={{
headerShown: true,
}}
>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Accounts" component={AccountsScreen} />
<Drawer.Screen name="Categories" component={CategoriesTabScreens} />
<Drawer.Screen name="Trends" component={TrendsScreen} />
<Drawer.Screen name="Favourites" component={FavouritesScreen} />
<Drawer.Screen name="Settings" component={SettingsScreen} />
</Drawer.Navigator>
);
};
export default AppDrawer;
Output
the result I want
Just use Style prop in Tab.navigator
Here is snack
https://snack.expo.io/#anthowm/drawer-navigation-%7C-react-navigation
const Tab = createMaterialTopTabNavigator();
const CategoriesTabScreens = () => {
return (
<Tab.Navigator
initialRouteName="Income"
tabBarOptions={{
indicatorStyle: {
height: Dimensions.get("window").height,
backgroundColor: "#29416F",
},
activeTintColor: "#fff",
inactiveTintColor: "#333",
}}
style={{paddingHorizontal: 24, marginTop: 40}}
>
<Tab.Screen name="Income" component={() => (<View style={{marginTop: 20}}><Text>INCOME</Text></View>)} />
<Tab.Screen name="Expense" component={() => (<View style={{marginTop: 20}}><Text>EXPENSE</Text></View>)} />
</Tab.Navigator>
);
};

Resources