Material Bottom bar

Material Bottom bar

Material Bottom Bar is an Android library that let you implement a customized BottomAppBar and a bottom drawer with just few simple steps.

Dsl ready

Navigation Component ready

Wiki

Full wiki

Docs

MaterialBottomBar Doc

Navigation Doc

Setup

Add the library:

implementation "studio.forface.materialbottombar:materialbottombar:$version"

Add the optional navigation extension:

implementation "studio.forface.materialbottombar:materialbottombar-navigation:$version"

Getting started

Layout ( minimal )

First you need to use a MaterialBottomDrawerLayout as parent of MaterialBottomAppBar.

<studio.forface.materialbottombar.layout.MaterialBottomDrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawerLayout"        
    android:layout_width="match_parent"    
    android:layout_height="match_parent">
 
 <!-- Here it goes your content -->
    
    <studio.forface.materialbottombar.appbar.MaterialBottomAppBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"/>
     
</studio.forface.materialbottombar.layout.MaterialBottomDrawerLayout>

More info about MaterialBottomDrawerLayout and MaterialBottomAppBar

Drawer ( minimal )

with DSL
drawerLayout.drawer = drawer {
    header {
        iconUrl = IMAGE_URL
        titleText = "My drawer"
    }
    body {
        onItemClick = { id, title -> /* do something */ }
        primaryItem( "Messages" ) {
            id = 1
            iconResource = R.drawable.ic_message_black_24dp
        }
        primaryItem( contactsSpannable ) {
            id = 2
            iconDrawable = contactsDrawable
        }
        divider()
        primaryItem( R.string.settings_drawer_title ) {
            id = 3
            iconBitmap = settingsBitmap
        }
    }
}

without DSL:

val header = MaterialDrawer.Header()
    .iconUrl( IMAGE_URL )
    .titleText( "My drawer" )
     
val messages = PrimaryDrawerItem()
    .id( 1 ) 
    .titeText( "messages" )
    .iconResource( R.drawable.ic_message_black_24dp )

val contacts = PrimaryDrawerItem()
    .id( 2 )
    .titleSpannable( contactsSpannable )
    .iconDrawable( contactsDrawable )

val settings = PrimaryDrawerItem()
    .id( 3 )
    .titleRes( R.string.settings_drawer_title )
    .iconBitmap( settingsBitmap )

val body = MaterialDrawer.Body()
    .itemClikListener { id, title -> /* do something */ }
    .items( listOf(
        messages,
        contacts,
        Divider(),
        settings
    ) ) 

drawerLayout.drawer = MaterialDrawer( header, body )

More info about Drawer and Panels

Android Navigation Components integration

with DSL ( constructor injected NavController )
navDrawer( navController ) {
    header { ... }
    body {
        primaryItem( "messages" ) {
            navDestinationId = myDestinationId
            navDestinationBundle = myBundle
        }
        primaryItem( "contacts" ) {
            navDestination( myDestinationId ) { mapOf( "arg1" to 15 ) }
        }
        secondaryItem( "favorites" ) {
            navDirections = myNavDirections
        }
    }
}
NavController can also be set later
navDrawer {
    ...
}
in the following ways:
  • myNavDrawer.navController = navController
  • myToolbar.setupWithNavController( navController, myNavDrawer, myNavPanel1, myNavPanel2 )
  • myMaterialBottomDrawerLayout.setupWithNavController( navController )
without DSL
val header = MaterialDrawer.Header()
    .iconUrl( IMAGE_URL )
    .titleText( "My drawer" )

val messages = PrimaryNavDrawerItem()
    .titeText( "messages" )
    .navDestination( myDestinationId )
    .navDestinationBundle( myBundle )
    
val contacts = PrimaryNavDrawerItem()
    .titeText( "contacts" )
    .navDestination( myDestinationId ) { mapOf( "arg1" to "hello" ) }

val body = MaterialNavPanel.Body()
    .itemClickListener { id, title -> /* do something */ }
    .items( listOf( messages, contacts ) )

drawerLayout.drawer = MaterialNavDrawer( header, body )

TIPS

The lib is built on 3 focal points:

  • Customization
  • Easiness
  • Compactness

The first two are pretty self-explanatory, while the third one means that you should be able to write your fully customized Drawer with the less lines of code as possible; in other word is suggested to use an approach like this:

with DSL:

drawer {
    header { ... }
    body {
        val myBadge = Badge {
            backgroundCornerRadiusDp = 999f // Round badge
            backgroundColorRes = R.color.color_badge_background
            contentColorRes = R.color.color_badge_content
        }
        allPrimary { 
            badgeItem = myBadge 
            titleSizeSp = 20f
            titleColor = Color.RED
        }
        primaryItem( "First" ) { badgeContentText = "1" " }
        primaryItem( "Second" ) { /* No badge content, so the badge will be hidden */ }
    }
}

withou DSL:

val myBadge = BadgeItem()
    .backgroundCornerRadiusDp( 999f ) // Round badge
    .backgroundColorRes( R.color.color_badge_background )
    .contentColorRes( R.color.color_badge_content )

class MyPrimaryDrawerItem() { init {
    badge( myBadge )
    titleSizeSp( 20f )
    titleColor( Color.RED )
} }

val firstItem = MyPrimaryDrawerItem()
    .titleText( "First")
    .badgeContentText( "1" )

val secondItem = MyPrimaryDraweItem()
    .titleText( "Second" )
    // No badge content, so the badge will be hidden.