React Navigation navigation Tutorial for beginners | Custom Tab and custom drawer Navigators

React Native Android IOS React Native Tutorial drawer React Navigation navigation Custom Tab

In this article, I am going to introduce a custom side menu drawer and bottom tab UI. Along with learning the awesome side menu drawer and bottom tabs animation UI implementation in React Native, we will also learn how its coding workflows and structures work.


Set-up and Installation

We are using the latest React navigation 6 for switching between the screens. To use this, we have to do some installation. So, let’s install that. 


For Navigation

npm install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs @react-navigation/drawer
npm install react-native-screens react-native-safe-area-context
or
yarn add @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs @react-navigation/drawer
yarn add react-native-screens react-native-safe-area-context


After installing dependencies run this command for iOS:

npx pod-install

Initiate Navigation in React Native

In this step, we will configure routes in our React native app. In order to enable navigation, we need to create home, profile, notification, and setting screens.

We are all set with the basic React native project, now we have to create the four screens.

mkdir screens
touch screens/home/home.tsx
touch screens/notification/notification.tsx
touch screens/profile/profile.tsx touch screens/setting/setting.tsx

After adding code homeScreen, notificationScreen, profileScreen and settingScreen file

homeScreen.tsx

/* eslint-disable prettier/prettier */

import { SafeAreaView, Text, View } from "react-native";
import React from 'react';
import Icon from 'react-native-vector-icons/Ionicons';

function HomeScreen() {
    return (
        <SafeAreaView style={{flex:1}}>
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor:'#3BB9FF' }}>
                <Text>Home Screen</Text>
                <Icon name={'ios-home'} size={22} color={'#000'} />
            </View>
        </SafeAreaView>
    );
  }

export default HomeScreen;

notificationScreen.tsx

/* eslint-disable prettier/prettier */

import { SafeAreaView, Text, View } from "react-native";
import React from 'react';


function NotificationScreen() {
    return (
        <SafeAreaView style={{flex:1}}>
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor:'#B666D2' }}>
                <Text>Ntification Screen</Text>
            </View>
        </SafeAreaView>
    );
  }

export default NotificationScreen;

profileScreen.tsx

/* eslint-disable prettier/prettier */

import { SafeAreaView, Text, View } from "react-native";
import React from 'react';


function ProfileScreen() {
    return (
        <SafeAreaView style={{flex:1}}>
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor:'#007C80' }}>
                <Text>Profile Screen</Text>
               
            </View>
        </SafeAreaView>
    );
  }

export default ProfileScreen;

settingScreen.tsx

/* eslint-disable prettier/prettier */

import { SafeAreaView, Text, View } from "react-native";
import React from 'react';


function SettingScreen() {
    return (
        <SafeAreaView style={{flex:1}}>
            <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor:'#387C44' }}>
                <Text>Setting Screen</Text>
            </View>
        </SafeAreaView>
    );
  }

export default SettingScreen;


After Open App.tsx file and add the following code:
/* eslint-disable prettier/prettier */
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 */

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import React from 'react';
import 'react-native-gesture-handler';
import {
  LogBox,
  SafeAreaView,
  useColorScheme,
} from 'react-native';

import {
  Colors,
} from 'react-native/Libraries/NewAppScreen';
import BottomTabNavigator from './navigations/bottomTabNavigator';
import DrawerNavigator from './navigations/drawerNavigator';

const Stack = createNativeStackNavigator();
LogBox.ignoreLogs(['Warning: ...']); // Ignore log notification by message
LogBox.ignoreAllLogs();

function App(): JSX.Element {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
    flex: 1,
  };

  return (
    <SafeAreaView style={backgroundStyle}>
      <NavigationContainer>
        <Stack.Navigator initialRouteName='Home' screenOptions={{headerShown:false}}>
          <Stack.Screen name="Home" component={DrawerNavigator} />
        </Stack.Navigator>
      </NavigationContainer>
    </SafeAreaView>
  );
}

export default App;

After creating navigations folder inner the src folder and creating the drawerNavigator.tsx and bottomTabNavigator.tsx files and add the following code : 

drawerNavigator.tsx

/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable prettier/prettier */
import React from "react";
import { createDrawerNavigator } from '@react-navigation/drawer';
import BottomTabNavigator from "./bottomTabNavigator";
import Icon from "react-native-vector-icons/Ionicons";
import CustomDrawer from "../components/customDrawer";
import ProfileScreen from "../screens/profile/profileScreen";
import NotificationScreen from "../screens/notification/notificationScreen";
import SettingScreen from "../screens/setting/settingScreen";

const Drawer = createDrawerNavigator();

const DrawerNavigator = () => {
    return(
    <Drawer.Navigator 
        drawerContent={props => <CustomDrawer {...props} />}
        screenOptions={{
        headerShown: false,
        drawerActiveBackgroundColor: "#B666D2",
        drawerActiveTintColor: "#fff",
        drawerLabelStyle: {
            marginLeft: -20,
        },
        }}>

        <Drawer.Screen name={"Home Drawer"} initialParams={{ params: 'feed' }} component={BottomTabNavigator} options={{ 
            title:"Feed",
            drawerIcon : ({focused, color, size}) =>(
                <Icon name="home-sharp" size={18} color={color} />
            )
        }} />

        <Drawer.Screen name={"Profile"}  initialParams={{ params: 'Profile' }} component={BottomTabNavigator} options={{
            title:"Profile", 
            drawerIcon : ({focused, color, size}) =>(
                <Icon name="ios-person-circle-sharp" size={18} color={color} />
            )
        }} />

        <Drawer.Screen name={"Notification"} initialParams={{ params: 'Notification' }} component={BottomTabNavigator} options={{
            title:"Notification", 
            drawerIcon : ({focused, color, size}) =>(
                <Icon name="ios-notifications-circle" size={18} color={color} />
            )
        }} />

        <Drawer.Screen name={"Settings"} initialParams={{ params: 'Settings' }} component={BottomTabNavigator} options={{
            title:"Settings", 
            drawerIcon : ({focused, color, size}) =>(
                <Icon name="settings-sharp" size={18} color={color} />
            )
        }} />
        
    </Drawer.Navigator>
    )
}

export default DrawerNavigator;

bottomTabNavigator.tsx

/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable react/no-unstable-nested-components */
/* eslint-disable prettier/prettier */
import React from "react";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import HomeScreen from "../screens/home/homeScreen";
import ProfileScreen from "../screens/profile/profileScreen";
import NotificationScreen from "../screens/notification/notificationScreen";
import SettingScreen from "../screens/setting/settingScreen";
import Icon from "react-native-vector-icons/Ionicons";
import { Platform, StyleSheet, TouchableOpacity } from "react-native";
import CustomTabBarButton from "../components/customTabBarButton";
import CustomTabBar from "../components/customTabBar";
import { useNavigation } from "@react-navigation/native";
Icon.loadFont();

const Tab = createBottomTabNavigator();

function BottomTabNavigator(props) {
  const navigation = useNavigation();
  console.log("navigation", props)
  return (
    <Tab.Navigator
      initialRouteName={props.route && props.route.params && props.route.params.params?props.route.params.params:'feed'}
      tabBar={props => <CustomTabBar {...props} />}
      screenOptions={(route)=>({
      headerShown:false,
      tabBarShowLabel:false,
      tabBarStyle:styles.tabBarStyle,
      tabBarActiveTintColor:"#B666D2", 
      tabBarInactiveTintColor:"#c1c1c1", 
      tabBarIcon:({color, size, focused}:any)=>{
        let iconName;
        if(route.route.name === "feed"){
          iconName = focused ? "ios-home-sharp" : "ios-home-outline";
        }else if(route.route.name === "Profile"){
          iconName = focused ? "ios-person-circle-sharp" : "ios-person-circle-outline";
        }else if(route.route.name === "Notification"){
          iconName = focused ? "ios-notifications-circle" : "ios-notifications-circle-outline";
        }else if(route.route.name === "Settings"){
          iconName = focused ? "settings-sharp" : "ios-settings-outline";
        }
        return <Icon name={iconName} size={22} color={color} />
      // eslint-disable-next-line comma-dangle
      }
      })}>
      <Tab.Screen name="feed" component={HomeScreen} options={{
        tabBarLabel:"Feeds",
        title:"Feed",
        headerShown:true,
        tabBarButton: props => (<CustomTabBarButton route="feed" {...props} />),
        headerLeft:() =>{
          return (
            <TouchableOpacity style={{paddingLeft:10}} onPress={() => navigation.openDrawer()}>
              <Icon name={Platform.OS === 'ios' ? 'ios-menu': 'md-menu'} size={30} color={'#222'} style={{marginRight:10}} />
            </TouchableOpacity>
          )
        }
      }} />
      <Tab.Screen name="Profile" component={ProfileScreen} options={{
        tabBarLabel:"Profile",
        title:"Profile",
        headerShown:true,
        tabBarButton: props => <CustomTabBarButton {...props} />,
        headerLeft:() =>{
          return (
            <TouchableOpacity style={{paddingLeft:10}} onPress={() => navigation.openDrawer()}>
              <Icon name={Platform.OS === 'ios' ? 'ios-menu': 'md-menu'} size={30} color={'#222'} style={{marginRight:10}} />
            </TouchableOpacity>
          )
        }
      }} />
      <Tab.Screen name="Notification" component={NotificationScreen} options={{
         tabBarLabel:"Notification",
         title:"Notification",
         headerShown:true,
        tabBarButton: props => <CustomTabBarButton {...props} />,
        headerLeft:() =>{
          return (
            <TouchableOpacity style={{paddingLeft:10}} onPress={() => navigation.openDrawer()}>
              <Icon name={Platform.OS === 'ios' ? 'ios-menu': 'md-menu'} size={30} color={'#222'} style={{marginRight:10}} />
            </TouchableOpacity>
          )
        }
      }} />
      <Tab.Screen name="Settings" component={SettingScreen}  options={{
        tabBarLabel: "Settings",
        title:"Settings",
        headerShown:true,
        tabBarButton: props => <CustomTabBarButton {...props} />,
        headerLeft:() =>{
          return (
            <TouchableOpacity style={{paddingLeft:10}} onPress={() => navigation.openDrawer()}>
              <Icon name={Platform.OS === 'ios' ? 'ios-menu': 'md-menu'} size={30} color={'#222'} style={{marginRight:10}} />
            </TouchableOpacity>
          )
        }
      }} />
    </Tab.Navigator>
  );
}
export default BottomTabNavigator;

const styles = StyleSheet.create({

  tabBarStyle:{
    backgroundColor:'transparent',
    position:'absolute',
    borderTopWidth:0,
    bottom:15,
    right:0,
    left:0,
    height:55,
  }

});

After Creating a components folder inner the src folder and creating the customDrawer.tsx,customTabBar.tsx and customTabBarButton.tsx file and add the following code:


customDrawer.tsx

/* eslint-disable prettier/prettier */
import { DrawerContentScrollView, DrawerItemList } from "@react-navigation/drawer";
import React from "react";
import { Dimensions, Image, ImageBackground, StyleSheet, View } from "react-native";

const {width} = Dimensions.get('screen');

const CustomDrawer = props =>{

    return (
        <DrawerContentScrollView {...props}  contentContainerStyle={{flex: 1}}>
            <ImageBackground source={require("../../assets/images/julen-rey-azcona-S5I_EpHhXio-unsplash.jpg")} style={{height:140}}>
                <Image source={require("../../assets/images/camera-7726802.jpg")} style={styles.userImg} />
            </ImageBackground>
            <View style={styles.drawerListWrapper}>
                <DrawerItemList {...props} />
            </View>
        </DrawerContentScrollView>
    )

}

export default CustomDrawer;


const styles = StyleSheet.create({
    userImg:{
        width:110,
        height:110,
        borderRadius:110/2,
        position:'absolute',
        left:width/2-130,
        bottom:-110/2,
        borderWidth:4,
        borderColor:"#fff"
    },
    drawerListWrapper:{
        marginTop:65
    }
});
customTabBar.tsx

/* eslint-disable prettier/prettier */

import { BottomTabBar } from '@react-navigation/bottom-tabs';
import React from 'react';
import { StyleSheet, View } from 'react-native';


const CustomTabBar = props => {
    return (
        <View>
            <View style={styles.tabBar}>
                <BottomTabBar {...props} />
            </View>
        </View>
    );
}

export default CustomTabBar;

const styles = StyleSheet.create({
    tabBar : {
        position:'absolute',
        right:10,
        left:10,
        bottom:15,
        height:30,
        backgroundColor:"#fff",
        borderRadius:10,
        shadowColor:'#222',
        shadowOffset:{
            width:0, height:1,
        },
        shadowOpacity:0.25,
        shadowRadius:2, 
        elevation:3,
        // width: "100%",
        margin:0
    }
});
customTabBarButton.tsx

/* eslint-disable prettier/prettier */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import Svg, {Path} from 'react-native-svg';

const CustomTabBarButton = props => {
  const {route, children, accessibilityState, onPress} = props;

  if (accessibilityState.selected) {
    return (
      <View style={styles.btnWrapper}>
        <View style={{flexDirection: 'row'}}>
          <View
            style={[
              styles.svgGapFiller,
              {
                borderTopLeftRadius: route === 'home' ? 10 : 0,
              },
            ]}
          />
          <Svg width={71} height={58} viewBox="0 0 75 61">
            <Path
              d="M75.2 0v61H0V0c4.1 0 7.4 3.1 7.9 7.1C10 21.7 22.5 33 37.7 33c15.2 0 27.7-11.3 29.7-25.9.5-4 3.9-7.1 7.9-7.1h-.1z"
              fill={"#FFF"}
            />
          </Svg>
          <View
            style={[
              styles.svgGapFiller,
              {
                borderTopRightRadius: route === 'settings' ? 10 : 0,
              },
            ]}
          />
        </View>

        <TouchableOpacity
          activeOpacity={1}
          onPress={onPress}
          style={[styles.activeBtn]}>
          <Text>{children}</Text>
        </TouchableOpacity>
      </View>
    );
  } else {
    return (
      <TouchableOpacity
        activeOpacity={1}
        onPress={onPress}
        style={[
          styles.inactiveBtn,
          {
            borderTopLeftRadius: route === 'home' ? 10 : 0,
            borderTopRightRadius: route === 'settings' ? 10 : 0,
          },
        ]}>
        <Text>{children}</Text>
      </TouchableOpacity>
    );
  }
};

export default CustomTabBarButton;

const styles = StyleSheet.create({
    btnWrapper: {
      flex: 1,
      alignItems: 'center',
    },
    activeBtn: {
      flex: 1,
      position: 'absolute',
      top: -22,
      width: 50,
      height: 50,
      borderRadius: 50 / 2,
      backgroundColor: "#FFF",
      alignItems: 'center',
      justifyContent: 'center',
      paddingTop: 5,
    },
    inactiveBtn: {
      flex: 1,
      backgroundColor: "#FFF",
      justifyContent: 'center',
      alignItems: 'center',
    },
    svgGapFiller: {
      flex: 1,
      backgroundColor: "#FFF",
    },
});
Result:

React Native Android IOS React Native Tutorial drawer React Navigation navigation Custom Tab
Comments

AdBlock Detected!

Our website is made possible by displaying ads to our visitors. Please supporting us by whitelisting our website.