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”
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()
}
}
<?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>
<?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>
<!--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
Post a Comment