Android Bottom Navigation stays at the bottom of the screen providing navigation between top-level views in the app. This is introduced in design support library with backward compatibility. Bottom Navigation should be used when the app has three to five top-level navigations.

This article explains the basics of Bottom Navigation, combining it with Fragments. We also going to learn how to load the first fragment with grid data (using RecyclerView) by fetching JSON through HTTP call.

android-bottom-naviation-tutorial-using-fragments

1. Bottom Navigation

The Bottom Navigation can be easily added using BottomNavigationView component. You have to use gravitation or relative attributes to make it appear at the bottom of the screen.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <FrameLayout
        android:id="@+id/frame_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:itemBackground="@color/bgBottomNavigation"
        android:foreground="?attr/selectableItemBackground"
        app:itemIconTint="@android:color/white"
        app:itemTextColor="@android:color/white"
        app:menu="@menu/navigation" />

</android.support.design.widget.CoordinatorLayout>

Here few important attributes have to noted down.

app:menu — The menu resource file to display the navigation items along with icon and text.
app:itemBackground — Applies background color to bottom navigation.
app:itemTextColor — The text color of bottom navigation item.
app:itemIconTint — The icon color of bottom navigation item.

When to use Bottom Navigation?
As per the design specs, the below navigations should be used depending on the criteria.

> Navigation Drawer – Use when top-level navigation has more than six destinations.

> Tabs – Use when there are two navigational destinations.

> Bottom Navigation – Use when there are three to five top-level destinations.

Before going further, have a quick look at the design specifications of Bottom Navigation.

android-bottom-navigation-tutorial

Now let’s try it by creating a new project in Android Studio.

2. Creating New Project

1. Create a new project in Android Studio from File ⇒ New Project and select Basic Activity from templates.

2. Download this res folder and add the drawables to your project’s res. This folder contains necessary drawables required for bottom navigation items.

3. Make sure you have design support library in your build.gradle.

dependencies {
    implementation 'com.android.support:design:26.1.0'
}

4. Add below color, string values to your colors.xml and strings.xml.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#7b4bff</color>
    <color name="colorPrimaryDark">#6539ba</color>
    <color name="colorAccent">#FF4081</color>
    <color name="bgBottomNavigation">#fe485a</color>
</resources>
<resources>
    <string name="app_name">Bottom Navigation</string>
    <string name="title_shop">Shop</string>
    <string name="title_gifts">Gifts</string>
    <string name="title_cart">Cart</string>
    <string name="title_profile">Profile</string>
</resources>

5. As the Bottom Navigation items rendered using a menu file, create a new xml named navigation.xml under res ⇒ menu folder.

6. Open the layout file of main activity i.e activity_main.xml and add BottomNavigationView widget. Here we are also adding a FrameLayout to load the Fragments when the navigation item is selected.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="info.androidhive.bottomnavigation.MainActivity">

    <FrameLayout
        android:id="@+id/frame_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:itemBackground="@color/bgBottomNavigation"
        android:foreground="?attr/selectableItemBackground"
        app:itemIconTint="@android:color/white"
        app:itemTextColor="@android:color/white"
        app:menu="@menu/navigation" />

</android.support.design.widget.CoordinatorLayout>

7. Now open MainActivity.java and modify it as below.

> Here, OnNavigationItemSelectedListener will be called when the bottom navigation item is selected. For now we are just changing the toolbar title upon selecting the navigation item.

package info.androidhive.bottomnavigation;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;

import info.androidhive.bottomnavigation.fragment.CartFragment;
import info.androidhive.bottomnavigation.fragment.GiftsFragment;
import info.androidhive.bottomnavigation.fragment.ProfileFragment;
import info.androidhive.bottomnavigation.fragment.StoreFragment;
import info.androidhive.bottomnavigation.helper.BottomNavigationBehavior;

public class MainActivity extends AppCompatActivity {

    private ActionBar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toolbar = getSupportActionBar();

        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

        toolbar.setTitle("Shop");
    }

    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            Fragment fragment;
            switch (item.getItemId()) {
                case R.id.navigation_shop:
                    toolbar.setTitle("Shop");
                    return true;
                case R.id.navigation_gifts:
                    toolbar.setTitle("My Gifts");
                    return true;
                case R.id.navigation_cart:
                    toolbar.setTitle("Cart");
                    return true;
                case R.id.navigation_profile:
                    toolbar.setTitle("Profile");
                    return true;
            }
            return false;
        }
    };
}

If you run the app, you can see the bottom navigation displayed as shown below.

android-bottom-navigation-with-fragments

3. Adding Fragments

As we have the Bottom Navigation ready, let’s see how to switch views when the navigation menu item is selected. This can be done easily by using the Fragments.

Note: ViewPager shouldn’t be used when using Bottom Navigation as per design specs (Avoid using lateral motion to transition between views)

I am creating four fragments named StoreFragment, GiftsFragment, CartFragment and ProfileFragment.

8. Create new Fragment by going to File ⇒ New ⇒ Fragment ⇒ Fragment (Blank) and name it as StoreFragment.java. Likewise create other three fragments too.

9. Open MainActivity.java and modify bottom navigation listener as below to load the fragments in FrameLayout.

> loadFragment() – loads the Fragment into FrameLayout. The same method is called in OnNavigationItemSelectedListener callback by passing appropriate fragment instance.
> The logic needed for specific module goes into appropriate Fragment keeping the MainActivity clean.

package info.androidhive.bottomnavigation;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;

import info.androidhive.bottomnavigation.fragment.CartFragment;
import info.androidhive.bottomnavigation.fragment.GiftsFragment;
import info.androidhive.bottomnavigation.fragment.ProfileFragment;
import info.androidhive.bottomnavigation.fragment.StoreFragment;
import info.androidhive.bottomnavigation.helper.BottomNavigationBehavior;

public class MainActivity extends AppCompatActivity {

    private ActionBar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toolbar = getSupportActionBar();

        // load the store fragment by default
        toolbar.setTitle("Shop");
        loadFragment(new StoreFragment());
    }

    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            Fragment fragment;
            switch (item.getItemId()) {
                case R.id.navigation_shop:
                    toolbar.setTitle("Shop");
                    fragment = new StoreFragment();
                    loadFragment(fragment);
                    return true;
                case R.id.navigation_gifts:
                    toolbar.setTitle("My Gifts");
                    fragment = new GiftsFragment();
                    loadFragment(fragment);
                    return true;
                case R.id.navigation_cart:
                    toolbar.setTitle("Cart");
                    fragment = new CartFragment();
                    loadFragment(fragment);
                    return true;
                case R.id.navigation_profile:
                    toolbar.setTitle("Profile");
                    fragment = new ProfileFragment();
                    loadFragment(fragment);
                    return true;
            }

            return false;
        }
    };

    private void loadFragment(Fragment fragment) {
        // load fragment
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.frame_container, fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }

}

Now if you run the project you can see the fragments loaded when navigation is selected.

4. Implementing ShopFragment – Displaying Items in Grid

Now we’ll see how to implement the first fragment i.e ShopFragment which displays the shop items in a Grid fashion. For demonstration, I have created a sample json which contains few movies for sale. To implement this, all we have to do is, fetch json and display the data in RecyclerView in a grid format. To make the task simpler, follow my other article which explains the same.

https://api.androidhive.info/json/movies_2017.json

10. Open build.gradle and add RecyclerView, CardView, Volley and Glide dependencies.

dependencies {
    // RecyclerView
    compile 'com.android.support:recyclerview-v7:26.1.0'

    // CardView
    compile 'com.android.support:cardview-v7:26.1.0'

    // volley http library
    implementation 'com.android.volley:volley:1.0.0'
    implementation 'com.google.code.gson:gson:2.6.2'

    // glide image library
    implementation 'com.github.bumptech.glide:glide:4.3.1'
}

11. Create a class named MyApplication.java implement the class from Application. This is a singleton class in which volley library will be initiated.

package info.androidhive.bottomnavigation.app;

import android.app.Application;
import android.text.TextUtils;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;

public class MyApplication extends Application {

    public static final String TAG = MyApplication.class
            .getSimpleName();

    private RequestQueue mRequestQueue;

    private static MyApplication mInstance;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized MyApplication getInstance() {
        return mInstance;
    }

    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }

        return mRequestQueue;
    }

    public <T> void addToRequestQueue(Request<T> req, String tag) {
        // set the default tag if tag is empty
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }

    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }

    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

12. Open AndroidManifest.xml and add MyApplication to <application> tag. We also need INTERNET permission as we gonna make http calls.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.bottomnavigation">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:name=".app.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

13. Open the layout file of StoreFragment i.e fragment_store.xml and add below layout code. Here we are adding the RecyclerView component.

<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f1f5f7"
    tools:context="info.androidhive.bottomnavigation.fragment.StoreFragment">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingTop="10dp"
            android:text="New Release Films"
            android:textColor="#111"
            android:textSize="16dp" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:clipToPadding="false"
            android:scrollbars="vertical" />
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

14. Create an xml layout named store_item_row.xml under res ⇒ layout. This layout file will be used in RecyclerView adapter class to render single item.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.CardView
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_margin="@dimen/card_margin"
        android:clickable="true"
        android:elevation="3dp"
        android:foreground="?attr/selectableItemBackground"
        card_view:cardCornerRadius="@dimen/card_album_radius">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <ImageView
                android:id="@+id/thumbnail"
                android:layout_width="match_parent"
                android:layout_height="@dimen/album_cover_height"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:clickable="true"
                android:scaleType="fitXY" />

            <TextView
                android:id="@+id/title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/thumbnail"
                android:lines="2"
                android:paddingLeft="@dimen/album_title_padding"
                android:paddingRight="@dimen/album_title_padding"
                android:paddingTop="@dimen/album_title_padding"
                android:textColor="#111"
                android:textSize="11dp" />

            <TextView
                android:id="@+id/price"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/title"
                android:layout_marginRight="10dp"
                android:gravity="right"
                android:paddingBottom="@dimen/songs_count_padding_bottom"
                android:textColor="@color/colorAccent"
                android:textSize="11dp" />

        </RelativeLayout>

    </android.support.v7.widget.CardView>
</LinearLayout>

15. Create a class named Movie.java. This POJO class will be useful while parsing the json.

package info.androidhive.bottomnavigation;

public class Movie {
    String title;
    String image;
    String price;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }
}

16. Now open StoreFragment.java and add below code. For simplicity the RecyclerView adapter class StoreAdapter included in the same fragment.

> fetchStoreItems() Method fetches the movies json using Volley and serializes it using Gson.

> StoreAdapter class renders the movies in RecyclerView.

package info.androidhive.bottomnavigation.fragment;


import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.bumptech.glide.Glide;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.json.JSONArray;

import java.util.ArrayList;
import java.util.List;

import info.androidhive.bottomnavigation.Movie;
import info.androidhive.bottomnavigation.app.MyApplication;
import info.androidhive.bottomnavigation.R;

public class StoreFragment extends Fragment {

    private static final String TAG = StoreFragment.class.getSimpleName();
    private static final String URL = "https://api.androidhive.info/json/movies_2017.json";

    private RecyclerView recyclerView;
    private List<Movie> movieList;
    private StoreAdapter mAdapter;

    public StoreFragment() {
        // Required empty public constructor
    }

    public static StoreFragment newInstance(String param1, String param2) {
        StoreFragment fragment = new StoreFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_store, container, false);

        recyclerView = view.findViewById(R.id.recycler_view);
        movieList = new ArrayList<>();
        mAdapter = new StoreAdapter(getActivity(), movieList);

        RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 3);
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(8), true));
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(mAdapter);
        recyclerView.setNestedScrollingEnabled(false);

        fetchStoreItems();

        return view;
    }

    private void fetchStoreItems() {
        JsonArrayRequest request = new JsonArrayRequest(URL,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        if (response == null) {
                            Toast.makeText(getActivity(), "Couldn't fetch the store items! Pleas try again.", Toast.LENGTH_LONG).show();
                            return;
                        }

                        List<Movie> items = new Gson().fromJson(response.toString(), new TypeToken<List<Movie>>() {
                        }.getType());

                        movieList.clear();
                        movieList.addAll(items);

                        // refreshing recycler view
                        mAdapter.notifyDataSetChanged();
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // error in getting json
                Log.e(TAG, "Error: " + error.getMessage());
                Toast.makeText(getActivity(), "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });

        MyApplication.getInstance().addToRequestQueue(request);
    }

    public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

        private int spanCount;
        private int spacing;
        private boolean includeEdge;

        public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
            this.spanCount = spanCount;
            this.spacing = spacing;
            this.includeEdge = includeEdge;
        }

        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view); // item position
            int column = position % spanCount; // item column

            if (includeEdge) {
                outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
                outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

                if (position < spanCount) { // top edge
                    outRect.top = spacing;
                }
                outRect.bottom = spacing; // item bottom
            } else {
                outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
                outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
                if (position >= spanCount) {
                    outRect.top = spacing; // item top
                }
            }
        }
    }

    /**
     * Converting dp to pixel
     */
    private int dpToPx(int dp) {
        Resources r = getResources();
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));
    }

    class StoreAdapter extends RecyclerView.Adapter<StoreAdapter.MyViewHolder> {
        private Context context;
        private List<Movie> movieList;

        public class MyViewHolder extends RecyclerView.ViewHolder {
            public TextView name, price;
            public ImageView thumbnail;

            public MyViewHolder(View view) {
                super(view);
                name = view.findViewById(R.id.title);
                price = view.findViewById(R.id.price);
                thumbnail = view.findViewById(R.id.thumbnail);
            }
        }


        public StoreAdapter(Context context, List<Movie> movieList) {
            this.context = context;
            this.movieList = movieList;
        }

        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View itemView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.store_item_row, parent, false);

            return new MyViewHolder(itemView);
        }

        @Override
        public void onBindViewHolder(MyViewHolder holder, final int position) {
            final Movie movie = movieList.get(position);
            holder.name.setText(movie.getTitle());
            holder.price.setText(movie.getPrice());

            Glide.with(context)
                    .load(movie.getImage())
                    .into(holder.thumbnail);
        }

        @Override
        public int getItemCount() {
            return movieList.size();
        }
    }
}

Now if you run the app, you can see the ShopFragment displaying the movies in grid manner. Likewise you can implement other fragments too.

android-bottom-navigation-with-fragments-recyclerview

5. Hiding Bottom Navigation on Scroll

As per design specs, the Bottom Navigation has to be hidden when the content is scrolled giving more room to content on the screen. To achieve this, we need to attach the BottomNavigationBehavior to Bottom Navigation.

17. Create a class named BottomNavigationBehavior.java with the below code.

package info.androidhive.bottomnavigation.helper;

import android.content.Context;
import android.support.design.widget.BottomNavigationView;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;

public class BottomNavigationBehavior extends CoordinatorLayout.Behavior<BottomNavigationView> {

    public BottomNavigationBehavior() {
        super();
    }

    public BottomNavigationBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, BottomNavigationView child, View dependency) {
        boolean dependsOn = dependency instanceof FrameLayout;
        return dependsOn;
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child, View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, BottomNavigationView child, View target, int dx, int dy, int[] consumed) {
        if (dy < 0) {
            showBottomNavigationView(child);
        } else if (dy > 0) {
            hideBottomNavigationView(child);
        }
    }

    private void hideBottomNavigationView(BottomNavigationView view) {
        view.animate().translationY(view.getHeight());
    }

    private void showBottomNavigationView(BottomNavigationView view) {
        view.animate().translationY(0);
    }
}

18. Add the BottomNavigationBehavior using setBehavior() in MainActivity.java as shown below.


public class MainActivity extends AppCompatActivity {

    private ActionBar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

        // attaching bottom sheet behaviour - hide / show on scroll
        CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) navigation.getLayoutParams();
        layoutParams.setBehavior(new BottomNavigationBehavior());

        // load the store fragment by default
        // ..
    }
}

Now if you test the app, you can see the Bottom Navigation sliding down when the app content is scrolled.

bottom navigation scroll listener
Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
  • Thank you Ravi! Marry Christmas! Can you double check the direct link for .APK file of this project, please? Thank you once again!

    • Hi Akkis,

      Happy Christmas you too 🙂 I just tried the apk, it’s working fine for me.

      Here is the link: http://download.androidhive.info/apk/bottom-navigation.apk

      • Thanks for the reply. Everything works fine now. Maybe mobile Chrome had an issue. Marry Christmas!

        • Ok Great 🙂

          • Protus Solutions

            Ravi thanks for the nice tutorial, please can you provide a tutorial on how to sync sqlite to mysql and mysql to sqlite most of the tutorials out there are not well done. pleaseeeeeee

          • I have to prepare one. Meanwhile you can check sync adapters from android docs.

          • Protus Solutions

            Much respect, I personally acquired a lot of knowledge through this blog. Keep the spirit alive. We will be waiting

          • Thanks Protus. I’ll do my best 🙂

  • Abdulwahid Mohammed

    I implement this lesson and got with error for nullpointer exception in the line
    MyApplication.getInstance().addToRequestQueue(request);
    This class is not created during the tutorial.
    how to do that?

    • Yes, I forgot few steps. Updated the article (added 11th and 12th steps), please check once.

      Thanks for pointing that out 🙂

      • Abdulwahid Mohammed

        Thank you very much sir.
        It is really helpful.

  • Andrew

    Add this android:name=”study.bottomnav2.app.MyApplication

    in androidmanifest.xml
    And app start on my phone

  • Adewale Salami

    Thank you Ravi, you are doing a good job by educating beginners like me with your knowledge. I have some challenges here. I am building a video player using recycler view to list all video files on my device and i am stuck. i want each row to include the title of the video, the size, date added and duration. could you help me out with a template code that i can study and improve on to achieve what i want. Thank you. Merry Xmas.

  • Abhishek Singh

    Thanks Ravi but there is a problem with bottom nav bar behaviour when we display snack bar it will hide below navigation bar if we use that behaviour.

    • Any screenshot?

      • Abhishek Singh

        Screenshot wont help because snackbar not showing just because for adding behaviour. not only me many people faced this see this is my answer on stackoverflow https://stackoverflow.com/a/44778453/7130121 people facing snackar issue thats why i came here to see implementation but your implementation is silimar. Do u have any idea what to do?

        • No Abhishek. I need a bit of research.

          • Besart Mahmuti

            Help please!

    • Besart Mahmuti

      I have the same problem , any respond from Ravi ?

  • Ahmad Faiz

    Hi Ravi, thank u for the good tutorial
    but i have same problem like on the tutorial CardView, my result just appear 3 card view and the shape just like pic… can u help me 🙁
    and the other problem is it take more time to load it, whats wrong??

    https://uploads.disquscdn.com/images/a341798b24eecda61b40f33987cac5213e8df2bc1a13a45b35506a3e7858603b.jpg

    • Sagar Chavda

      Please once check that store_item_row.xml root layout height must be a wrap_content.

      • Ahmad Faiz

        oh, great… thanks… solved

  • Sagar Chavda

    Hi @ravi8x:disqus , I’ve two question related to BottomNavigation and i expecting help from you.
    1. Here when we switch from Shop to Gift again click on Shop it’s go to fetch data again so, how can we avoid this and display first time loaded data?
    2. Here on Backpress backstack working fine but selected menu not changing according backstack?

    • Sagar Chavda

      @ravi8x:disqus can you please help me with above mentioned point ?

    • (This commend doesn’t appeared on my moderation panel, don’t know why)

      1. Here when we switch from Shop to Gift again click on Shop it’s go to fetch data again so, how can we avoid this and display first time loaded data?
      You can store the data in local storage like MySQL or Realm and show it directly. You can keep an interval like 5mins to fetch the new data.

      2. Here on Backpress backstack working fine but selected menu not changing according backstack?
      This has to done automatically by the navigation widget itself, unfortunately it is not. Try the code provided in the below discussion.
      https://stackoverflow.com/questions/44362819/on-back-press-traversing-through-last-two-tabs-not-working-properly-in-bottomnav?noredirect=1&lq=1

      3. If user Go Shop >> Gift >> Cart >> Gift so, now here how i can manage backstack enter duplication for e.g. remove old Gift backstack entry and in new position
      Answer of 2nd question should solve this issue by doing the changes in the logic.

  • Akhil Mankala

    Hi, i have a question. How to disable the animation when there are 5 items in the bottom navigation bar. I just want the icons to be static.

  • Maciej Frankowski

    Implemented, works great, thank U! 🙂 .

  • mang pali

    Hi @Ravi Tamada:disqus thanks to the tutorial.
    I have a question how to handle on rotation ? fragment changes if I rotate the emulator.

  • Michael Sandros

    Happy New Year to all.
    @ravi8x:disqus is there a problem with xml files? I can not find the dimen folder and i have some problems
    The compiler has problem to find the calls to dimen, for example “@dimen/card_album_radius”.

    Am I mssing something?

  • sonali kale

    Hello sir I want to use BottomNavigation on Tablet in landscape mode. can i use more than six destinations ?
    please ans me.

  • Rajat Das

    Hey I’m very happy because I found your blogs. Thanks for doing this great work for us… I have a Request to you that could you please make a complete series on how to make Android music player. Again thanks ☺️

    • Hi Rajat

      Try modifying and fixing the bugs in the current article. As not many people are asking for an update, I am giving it less priority.

  • mohamad

    Hi Ravi
    Thank you and Marry Christmas
    could you please make tutorial for working with map, like uber Application and its functionality
    Thank you so much and Marry Christmas again 😀

    • Thanks Mohamad. I wish you the same.

      I am working customizing maps. It will be published after couple of articles.

  • Michael Sandros

    @ravi8x:disqus
    happy new year,
    you could add the swipe left and right implementations for better app experience

  • លាវ ពន្លក

    very very thank you I like this article

  • Arash

    Hi , ty for this great article, i’m getting an XML error:
    Binary XML file line #16: Error inflating class android.support.design.widget.BottomNavigationView
    how can i fix this? please help me

    • Have you added the design support library in gradle?

  • viavitaeapps test

    Happy new year Ravi,,
    I have confusion regarding setting the jsonArray data to the POJO.Where you actually setting ?
    And how in the onBindViewHolder() we are getting the exact same data without setting first.

    Please elaborate this line -> List items = new Gson().fromJson(response.toString(), new TypeToken<List>() { }.getType());

    • Hi

      This is called JSON serialization. We can avoid manually parsing JSON by using GSon library. What we do is, keep the variable name same as JSON node name. While serializing it maps the JSON value with matched variable name in POJO class. If you want use different name for the variable, we can use annotations.

      Read the GSon documentation for better understating.

      Happy new year !

      • viavitaeapps test

        you are awesome bro….
        thanks for replying

  • Ashis Ranjan Dey

    how can I change background colour of bottom bar for each fragment? should I add something to onNavigationItemSelected() method?Thanks in advance

  • Ivkaran Singh

    Hello Ravi,

    Thanks a lot for this great tutorial.

    How can I have 4-6 cards of different categories on Page 1 with each having a View More button and when clicked under a specific category will take to the 2nd page which will have all the cards of the category.=?

  • Kutluhan Ozan Köse

    Hi Ravi, I am trying a sliding menu (navigation drawer) and bottom navigation draver in one activity. I placed everything correctly but when I click a fragment in the bottomnavigation it throws this;

    MainActivity must implement OnFragmentInteractionListener

    Will you help?

    • Seems there is an error in your layout files. Check all the layout files. You might be missing params of height and widget or other related attributes.

  • E Y

    Thanks Ravi for great tutorial. How to switch between fragments with rubbed by hand?

    • For that you need to use ViewPager but ViewPager shouldn’t be used with Bottom Navigation as per google desc specs. ViewPager navigation should be used with Tabs.

      • E Y

        Thanks for the information.

  • veer

    my fragments are not loaded … please help me..
    Thank You……..

  • Magesh R

    Hai bro, I got this error
    java.lang.NullPointerException in MyApplication.getInstance().addToRequestQueue(request);
    internet permission is also placed.
    Please help me bro

    • MyApplication class has to be added to AndroidManifest.xml <application> tag.

  • Magnusef

    Do you have a tutorial on how to cache the fragments, so I don’t have to load data every time I click the fragment?

  • Ghanshyam Tiwari

    thanks a lot

  • Samuel Iwuchukwu

    Wow..this tutorial is so simple and direct..thank you Ravi..you just saved me..
    @Uncle Sam

  • Aabhas Singhal

    Hi Ravi,
    Thanks for the tutorial
    I want to know how to stop reloading every time i click on the store fragment ?

    • hassan moradnezhad

      search about viewpager.setOffscreenPageLimit();

  • shiva pasunoori

    can i use relative layout instead o coordinator layout for hide the bottom navigation when we scroll fragment

    • You can but no guarantee of consistent experience on all the devices.

      • shiva pasunoori

        k Sir , One more Sir,Please prepare a expandable recycler view tutorial

  • Akash Mishra

    Can I change the first menu. I mean to say, like I add 3 menu and I want the mid one should be visible on activity launch. Is it possible?

  • Johannes Ramothale

    Thank for the tut, I have been stuck on bottom navigation for hours now. great work

  • Pin Number

    Did you notice java memory in android profile – it’s increasing as you click on menu items repeatedly?
    Is it a memory leak . I think it is bug in bottom navigation itself. Try without fragments just simple navigation piece with simple switch statement. Java memory increases but will not come down after waiting for long period.

  • Aleesa Javid

    Hi
    I have a question??
    In bottom navigation fragment i have one view.on click of view open a next activity..in next activity on click of back button open previous fragment but not show navigation bar…how i can resolvce this…

  • Mitesh Makwana

    Hi Ravi,
    how to stop bottom navigation animation ,
    my requirement is display bottom icon without any animation on click event

    • Mitesh Makwana

      i solve this problem after adding BottomNavigationViewHelper class it work fine

      thanks for this awesome tutorial

      • Sharing BottomNavigationViewHelper code may helps others.

        Thanks Mitesh.

        • Mitesh Makwana

          import android.support.design.internal.BottomNavigationItemView;
          import android.support.design.internal.BottomNavigationMenuView;
          import android.support.design.widget.BottomNavigationView;
          import android.util.Log;
          import java.lang.reflect.Field;

          public class BottomNavigationViewHelper {
          public static void disableShiftMode(BottomNavigationView view) {
          BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
          try {
          Field shiftingMode = menuView.getClass().getDeclaredField(“mShiftingMode”);
          shiftingMode.setAccessible(true);
          shiftingMode.setBoolean(menuView, false);
          shiftingMode.setAccessible(false);
          for (int i = 0; i < menuView.getChildCount(); i++) {
          BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
          //noinspection RestrictedApi
          item.setShiftingMode(false);
          // set once again checked value, so view will be updated
          //noinspection RestrictedApi
          item.setChecked(item.getItemData().isChecked());
          }
          } catch (NoSuchFieldException e) {
          Log.e("BNVHelper", "Unable to get shift mode field", e);
          } catch (IllegalAccessException e) {
          Log.e("BNVHelper", "Unable to change value of shift mode", e);
          }
          }
          }

          add this in your java file
          BottomNavigationViewHelper.disableShiftMode(navigation);

          • OmkarK

            thank you..! @Mitesh makwana

          • Mitesh Makwana

            welcome

  • Malik Mahmoud

    you can do a tutorial if you click on the RecyclerView to open a new activity (details)

    • Malik Mahmoud

      please Ravi

  • erick jayson deguzman

    hi sir @ravi8x:disqus , how to go to next activity when i click gifts , Tnx

  • nathan

    hi @ravi8x:disqus just wondering what version of android studio you are using because i am getting a few errors early on, null pointers etc.

    • nathan

      the main error that i get is java.lang.NullPointerException: Attempt to invoke virtual method ‘void android.support.v7.app.ActionBar.setTitle(java.lang.CharSequence)’ on a null object reference

      any ideas?

      • sidiq zaenal

        maybe MyApplication not added to AndroidManifest.xml? i think so

  • Try removing https from the url and try with http. If the server ssl certificate is poor, you will see this error.

    If you are using Retrofit, try adding SSL Ciphers from the featured comment below this article.
    https://www.androidhive.info/2016/05/android-working-with-retrofit-http-library/#disqus_thread

    Try in other devices as well. But in production app, the server should have good SSL certificate installed.

    • sidiq zaenal

      okay, problem solved and program running. Thank you Ravi 🙂

      • Great!

        • sidiq zaenal

          oh ya, untuk click item in recyclerview itu bagaimana cara mengimplementasikannya? terimakasih untuk jawabannya Ravi 🙂

  • karishma kumari

    hi Ravi,
    can we select a fragment without clicking on the navigation botton ? Is it possible ? I mean automatically to select position of navigationButton ?

  • Henrique Resende

    https://uploads.disquscdn.com/images/4aef815cef7b3ecd95cce14b15f9d9ee681f678a07ecebd956b1016881e85bfb.png When i write in CASE fragment = new InicioFragment();
    loadFragment(fragment);

    The android studio tell me that “fragment = new InicioFragment();” have a error that says “Incompatible types: Required : android.support.v4.app.Fragment / Found : com.example.henrique.tecardapk.InicioFragment”

    What i do?

    • sidiq zaenal

      In CodigoFragment replace import android.app.Fragment; become import android.support.v4.app.Fragment;

  • Malik Mahmoud

    hi @ravi8x:disqus you can do a tutorial if you click on the RecyclerView to open a new activity (details) ?

  • Azmi

    Hi @ravi8x:disqus, it’s very nice tutorial! Anyway i have a little problem:

    When i try to use Retrofit, i cannot access your link and when i go to the log, it says that the response code is 405, which means that my apps is not allowed to access your json code. Can you please help me?

    Thanks

    • Azmi

      i am just resolving this issue by following the answer from @sidiqzaenal:disqus question. My apologize 😉

  • sidiq zaenal

    Hi Ravi,

    I want to ask again 🙂 I want to change the size of the recyclerview item that is drawn below, right it every 1 line there are three items. Well I want to turn it into 2 items per line that how I’ve tried to change but it always fails. Thank you for Answare.
    https://uploads.disquscdn.com/images/9887826ec2a8315d3b1f6caa9db3e3acf950475ecbe704437a60248c3d31ae54.png

    • In your main activity change the number from 3 to 2 in the below line.
      RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getActivity(), 3);

      • sidiq zaenal

        oh yes, worked. Thanks you Ravi:)

    • Besart Mahmuti

      plz can u tell me the code of your API @sidiqzaenal:disqus i see that u have build your own database ,
      and im trying to fetch my data from database but im doing something wrong and i think is the API

  • Besart Mahmuti

    @ravi8x:disqus can u tell me the code of the API

  • Dino sunny

    Hi, How remove bottom navigation jumping animation? Bottom icons

  • Độ

    How to avoid reloading fragment when I click a tab again? @Ravi Tamada

  • sidiq zaenal

    Hi @ravi8x:disqus,
    I am still confused how to send fragment image to fragment, for example as the picture on thumbnail recyclerview is sent to DetailFragment. Can it be helped? maybe the picture like the picture below, I hope can be assisted by Ravi Tamada

    https://uploads.disquscdn.com/images/8d254a12d15acec8a346d90b5f1e443b70ce15c737d23c8c57f1b0b1d67f2557.png

    • Paste the code you used to launch the detailed activity or fragment.

      • sidiq zaenal

        holder.card.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

        sendname = holder.name.getText().toString();
        //is this like it or not? if you have a text that way just cuman image can not sendimage = holder.thumbnail.getContext().toString();
        sendprice = holder.price.getText().toString();

        FragmentTransaction fragmentTransaction=getFragmentManager().beginTransaction();
        DetailBarangFragment detailBarangFragment= new DetailBarangFragment();

        Bundle bundle = new Bundle();
        bundle.putString(“name”, sendname);
        //how to pass image in fragment to fragment ???????????????? bundle.putString(“thumbnail”, sendimage)
        bundle.putString(“price”, sendprice);
        detailBarangFragment.setArguments(bundle); //send data
        fragmentTransaction.replace(R.id.frame_container, detailBarangFragment);
        fragmentTransaction.isAddToBackStackAllowed();
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
        //Toast.makeText(getActivity(), movie.getTitle(), Toast.LENGTH_SHORT).show();
        }
        });

        • I am guessing you are displaying images from an Url. If yes, just pass the image url as String. On the detailed fragment, get the image url from the bundle arguments and display the image using Glide or Picasa.

          • sidiq zaenal

            So what source code Ravi? helpme:)

  • Леня Захаров

    https://uploads.disquscdn.com/images/1c95dbb64381045260155b926f96409fb60f313654dd324fbffe4e5360f242cf.png Hi @ravi8x:disqus ,
    I have an issue. All the images are loading, but all text is no. But, if i change holder.name.setText(movie.getTitle()); -> holder.name.setText(“Some Text”);
    It’s working. Helm me please))
    P.S. Sorry for grammar, i’am Russian 😉

    • Check the JSON node and variable name in Movie class. They should match or use @SerializedName annotation.

      • Леня Захаров

        Yeah, thanks, Its work

  • Леня Захаров

    Hi again @Ravi Tamada, And now I have a problem with hiding navBar . App is Just crash when I stat it. Debuger says that this happens when onCreate() in Bottom… Behavior

  • Леня Захаров

    Hi again @ravi8x:disqus , And now I have a problem with hiding navBar . App is Just crash when I stat it. I think problem in param navigation.getLayoutParams()

  • Tim Hannah

    Hi

    I have followed your tutorial perfectly have adapted it for my needs. However I would like to know how i would, instead of using your images on the page i could have button widgets and use an onclick to change the fragment keeping the nav bar at the bottom

    https://uploads.disquscdn.com/images/c0e05fb945d17e01892faf1dc6e5aa2d43d652cdb9101f5e7d3dcf912a147258.png

    This is what i have on one of my fragment pages. (a series of buttons) now how and where do i put the code for listening to button press’s and changing the fragment while keeping the bar at the bottom of the new page etc.

    • The button clicks should be implemented in Fragment itself. If you want to notify your main activity about the click, use interface to define a method in fragment and implement the method in main activity.

      • Tim Hannah

        Are you able to provide an example for me to try and implement. the structure of the code for both fragment and main are pretty much similar to your original code.

  • Jordan Chicote

    awesome, but how i create one more button to this menu? i want make a app with 5 buttons

    • Have you tried adding 5 items in navigation.xml? I have already shown the screenshot with 5 buttons.

  • Do you have actionBar included in your layout or from the theme?

  • Sumit Aditya

    how can i add click listener on this code ?

  • Nikhil Nagaraju

    whoever followed this tutorial be sure to use just the idea not the code… there are few leaks in StoreFragment, every time you load the fragment: memory increases. I guess its problem with ‘Rect’ for offseting the cards

  • andy app

    I have used same code, but getting this errror. I am new to android Please Help Me

    java.lang.NullPointerException: Attempt to invoke virtual method ‘void android.support.v7.app.ActionBar.setTitle(java.lang.CharSequence)’ on a null object reference

    • Make sure your activity has Toolbar included via xml or from the styles.

      • andy app

        Could you please help me

        • Are you able to run my code downloaded from this article?

          • andy app

            Yes, Thanks for help

  • OmkarK

    Hello sir thank you for this tuts…
    I have issue
    how to implement left/right sliding effect to this?

    • As per android docs, left / right sliding shouldn’t be used with Bottom Navigation.

      • OmkarK

        ohh my bad ! BTW thanks..

      • Mohamed helmy

        I know that left / right sliding shouldn’t be used with Bottom Navigation
        but app owner need it
        please tell me how

        • Try using a ViewPager and when page is swiped, change the navigation tab and vice-versa.

  • raksha

    Hii @ravi8x:disqus sir.I’m just a beginner as a Android Developer .My question is why we use Basic Activity instead of Bottom Navigation Activity in starting?

    • You can do that way once you have an idea about BottomNavigation. This is to know the behind scenes:)

  • Mitesh Makwana

    hii ravi,
    how to remove bottom title from bottom navigation?

  • chiruraja

    SIR CAN WE USE BOTH THE SIDE AND BOTTOM NAVIGATION’S AT ONCE IN THE SAME APP

    • We can but google guidelines not prefers that way.

  • Mitesh Makwana

    hii ravi,
    please male a tutorial on getting call details after call end’s from background service

    or any example

  • Kuldeep Kumar

    mBiodataExapandable = new BiodataExpandable(listModelBiodata, this);
    these line working in activity but not in a fregment .
    how can i used these lines in fragment.
    thanks sir

    • use `getActivity()` instead of `this`.

      mBiodataExapandable = new BiodataExpandable(listModelBiodata, getActivity());

  • Kuldeep Kumar

    can you explain how to make this page design which shows in image … https://uploads.disquscdn.com/images/aff8e9bceb1b3c2df73a4fda7ebfcd20a07ccdc9c0bb0823e8b21e05f09df64b.png

    • The two columns can be achieved by RecyclerView and Cards combined with StaggeredGridLayoutManager.

  • Kuldeep Kumar

    public void onClick(View v) {
    activity.getFragmentManager().beginTransaction().replace(R.id.upcoming,new UpcoomingContest()).addToBackStack(null).commit();

    }/// error in activity cannot resole

    • Can you post the complete error?

      • Kuldeep Kumar

        sir i have created upcoming contest fragment class. but i not handle in adapter click listner to open this fragment class, so can you help me how to open new fragment class on listing items click
        thanks

  • Mitesh Makwana

    how to create bottom navigation like instagram?
    with only icons

  • Harika Rathnala

    error: resource string/action_settings (aka com.example.bottomview:string/action_settings) not found
    error: failed linking file resources. I am getting these 2 errors .pls help me in rectifying these errors

  • Michael “Tosh” Evans

    please email me the json file

  • raksha

    Hello sir, I want to connect 3 cardviews(in 3 different activities) in single project.Bt m not sure about the interface code n also have couple of doubts:

    1.can we use single cardview n recyclerview code for 3 or more activities?

    2.How to connenct the 3 cardviews to each other?
    3.Plz give me d idea on :””””On clicking 1st card next activity(also contains cardview) get opened n on clicking any card of 2nd activity 3rd activity(also contain cardview)get opened”””

  • Tarik M’ghari

    For the people who’s asking about if you have an EDITTEXT in the fragment , the bottom nav displays above the keyboard you should ass this line

    android:windowSoftInputMode=”adjustPan”

    in Androidmanifest.xml in the main Activity

  • Tarik M’ghari

    Hello Ravi thank u for your tutorials . I am displaying data in a recycler view like you did but the problem is insert data in that recyclerview in the same fragment so i’d like to reload the fragment when i insert the data is that possible ?

  • Tarik M’ghari
  • ashish

    hello i want to show badge at bottom navigation

  • صديقك للمعرفة

    can i use this code in my app or He has property rights

    • You can use it freely. Thanks for asking 🙂

  • Vaibhav Kabadwal

    I want to show shadow in my custom made bottom navigation bar. I have tried many options but none of them is working for me. Kindly help.