Bottom Navigation or Navigation bar - Android Material UI/UX

Navigation bars offer a persistent and convenient way to switch between primary destinations in an app.

There's one type of navigation bar in Material. In M2, this component is named bottom navigation.

A BadgeDrawable represents dynamic information such as a number of pending requests in a BottomNavigationView or TabLayout.

Takeaways

  • The position of the navigation bar makes primary user journeys easy to access on mobile devices.
  • Items in the navigation bar remain consistent in their destination assignment, placement, and interaction behavior across an app.
  • Navigation items should be relatively equal in importance.

What's new

  • Color: New color mappings and compatibility with dynamic color
  • Elevation: No shadow
  • Layout: Container height is taller
  • States: The active destination can be indicated with a pill shape in a contrasting color
  • Name: Bottom navigation has been renamed “navigation bar”

Fragment:
package com.boltuix.materialuiux

import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.boltuix.materialuiux.databinding.BottomNavigationBadgeBinding
import com.google.android.material.badge.BadgeDrawable
import kotlin.math.roundToInt

/*
* Bottom navigation bars allow movement between primary destinations in an app
* */
class BottomNavigationFragment : Fragment() {

    private var handler: Handler = Handler(Looper.myLooper()!!)
    var runnable: Runnable? = null

    private var _binding: BottomNavigationBadgeBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {

        _binding = BottomNavigationBadgeBinding.inflate(inflater, container, false)
        return binding.root

    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)




        try{
            handler.postDelayed(Runnable {

                // * Badge dot, 1 sec delay
                val badgeFav: BadgeDrawable = binding.navigation.getOrCreateBadge(R.id.navigation_favorites)
                badgeFav.isVisible = true
                badgeFav.verticalOffset = dpToPx(requireActivity(), 3)
                badgeFav.backgroundColor = ContextCompat.getColor(requireContext(), R.color.pink_500)
            }.also { runnable = it }, 1000)
        }catch (e:Exception){}

        // * Badge number
        val badgeBook: BadgeDrawable = binding.navigation.getOrCreateBadge(R.id.navigation_books)
        badgeBook.isVisible = true
        badgeBook.verticalOffset = dpToPx(requireActivity(), 3)
        badgeBook.number = 88
        badgeBook.backgroundColor = ContextCompat.getColor(requireContext(), R.color.pink_500)

    }


    override fun onStop() {
        super.onStop()

        // need to remove handler call back when page destroy
        if(runnable!=null){
            handler.removeCallbacks(runnable!!)
        }
    }
    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    private fun dpToPx(c: Context, dp: Int): Int {
        val r = c.resources
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            dp.toFloat(),
            r.displayMetrics).roundToInt()
    }


}
..
In this code:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:background="@color/grey_5">

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


        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:ignore="UselessParent">

            <LinearLayout
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:orientation="vertical"
                tools:ignore="UselessParent">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal">

                    <ImageView
                        android:layout_width="50dp"
                        android:layout_height="50dp"
                        android:layout_marginEnd="@dimen/spacing_mlarge"
                        android:src="@drawable/shape_circle"
                        app:tint="@color/grey_20" />

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

                        <View
                            android:layout_width="70dp"
                            android:layout_height="@dimen/spacing_middle"
                            android:background="@color/grey_20" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="@dimen/spacing_middle"
                            android:layout_marginTop="@dimen/spacing_middle"
                            android:background="@color/grey_20" />

                        <View
                            android:layout_width="40dp"
                            android:layout_height="@dimen/spacing_middle"
                            android:layout_marginTop="@dimen/spacing_middle"
                            android:background="@color/grey_20" />

                    </LinearLayout>

                </LinearLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/spacing_large"
                    android:orientation="horizontal">

                    <ImageView
                        android:layout_width="50dp"
                        android:layout_height="50dp"
                        android:layout_marginEnd="@dimen/spacing_mlarge"
                        android:src="@drawable/shape_circle"
                        app:tint="@color/grey_10" />

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

                        <View
                            android:layout_width="100dp"
                            android:layout_height="@dimen/spacing_middle"
                            android:background="@color/grey_10" />

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="@dimen/spacing_middle"
                            android:layout_marginTop="@dimen/spacing_middle"
                            android:background="@color/grey_10" />

                        <View
                            android:layout_width="40dp"
                            android:layout_height="@dimen/spacing_middle"
                            android:layout_marginTop="@dimen/spacing_middle"
                            android:background="@color/grey_10" />

                    </LinearLayout>

                </LinearLayout>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/spacing_large"
                    android:text="Bottom Navigation badge"
                    android:textAppearance="@style/Base.TextAppearance.AppCompat.Small"
                    android:textColor="@color/grey_40" />

            </LinearLayout>

        </RelativeLayout>

    </LinearLayout>

    <!-- search bar layout -->
    <include
        android:id="@+id/search_bar"
        layout="@layout/include_card_view_search_bar" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/navigation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom"
        app:elevation="15dp"
        app:itemIconTint="@color/md_theme_light_primary"
        app:itemTextColor="@color/md_theme_light_primary"
        app:menu="@menu/menu_bottom_navigation_badge" />
</RelativeLayout>
..
In menu: menu_bottom_navigation_badge.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/navigation_favorites"
        android:icon="@drawable/ic_favorites"
        android:title="Favorites" />

    <item
        android:id="@+id/navigation_music"
        android:icon="@drawable/ic_music"
        android:title="Music" />

    <item
        android:id="@+id/navigation_books"
        android:icon="@drawable/ic_news"
        android:title="Books" />

    <item
        android:id="@+id/navigation_newsstand"
        android:icon="@drawable/ic_receipt_long"
        android:title="News" />

</menu>
..
In value folder: dimens.xml
 <!--genaral spacing-->
    <dimen name="spacing_xsmall">2dp</dimen>
    <dimen name="spacing_small">3dp</dimen>
    <dimen name="spacing_medium">5dp</dimen>
    <dimen name="spacing_xmedium">7dp</dimen>
    <dimen name="spacing_middle">10dp</dimen>
    <dimen name="spacing_large">15dp</dimen>
    <dimen name="spacing_smlarge">18dp</dimen>
    <dimen name="spacing_mlarge">20dp</dimen>
    <dimen name="spacing_mxlarge">25dp</dimen>
    <dimen name="spacing_xlarge">35dp</dimen>
..
..


Comments