Android: Custom Toolbar

Romman Sabbir
5 min readDec 27, 2020

--

Toolbar is a core component in terms of mobile UI design. We generally use Toolbar that comes with the Platform SDK, but I like to do design my own custom toolbar for general purpose or for some additional purpose.

Use case:

  • When you have custom design instead of a Standard Toolbar Design
  • When you follow a template base package for all of your projects
  • Reduce the code complexity, fragment the codes to respective class and expose some API to play with the toolbar
  • When you follow the Single Activity Architecture
  • When you want to Explore (I love to explore)

Prerequisite :

  • Builder Design Pattern
  • Android Navigation
  • Understanding of DataBinding
  • Higher Order Function (Kotlin)

Let’s create our own custom layout.

First: Design the custom Toolbar UI

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

<data>

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:id="@+id/toolbar_root_layout"
android:layout_height="wrap_content">

<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="56dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_toolbar">

<TextView
android:id="@+id/tv_toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/ubuntu_light"
android:text="Custom Toolbar"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageButton
android:id="@+id/iv_toolbar_back"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="8dp"
android:background="?actionBarItemBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_baseline_arrow_back_24" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Note:

  1. Root ConstraintLayout id is `toolbar_root_layout`
  2. Card View height is `56dp`, standard size for Toolbar
  3. Back button (ImageButton) background is set to `?actionBarItemBackground` to provide an ripple effect the button is pressed

4. Toolbar title id is `tv_toolbar_title` and Toolbar back button id is `iv_toolbar_back`

You can customize the UI based on your requirment.

Second: Lets build the API to handle actions or manipulate our custom toolbar

/**
* This class represent the Custom Toolbar API for clients.
* Lets make the constructor private because we will use
* Builder Design Pattern to initialize the API
*/
class AppToolbar private constructor() {

companion object {
/*
Custom toolbar binding reference
*/
private var binding: ContentCustomToolbarBinding? = null

/**
* To initialize [AppToolbar] client have to use this [Builder]
* class to provide the custom toolbar reference [ContentCustomToolbarBinding]
*
*/
class Builder {

/**
* Set the binding provided by client
*
*
@param binding, [ContentCustomToolbarBinding]
*
@return [Builder]
*/
fun withBinding(binding: ContentCustomToolbarBinding): Builder {
AppToolbar.binding = binding
return this
}

/**
* This method check for the binding reference validation.
* If validation is not valid, `throw` a new [Exception]
* Else initialize the [AppToolbar] class and return the instance
*
*
@return [AppToolbar]
*/
@Throws(Exception::class)
fun build(): AppToolbar {
when (binding) {
null -> {
throw Exception("Binding reference can not be null")
}
}
return AppToolbar()
}
}
}

/**
* Hide or show the toolbar
*
*
@param isEnabled, [Boolean]
*
@return [AppToolbar]
*/
fun enableToolbar(isEnabled: Boolean): AppToolbar {
binding?.toolbarRootLayout?.setVisibility(isEnabled)
return this
}

/**
* Update the title
*
*
@param title, [String]
*
@return [AppToolbar]
*/
fun updateTitle(title: String): AppToolbar {
binding?.tvToolbarTitle?.text = title
return this
}

/**
* Show or hide the back button
*
*
@param isEnabled , [Boolean]
*
@return [AppToolbar]
*/
fun enableBackBtn(isEnabled: Boolean): AppToolbar {
binding?.ivToolbarBack?.setVisibility(isEnabled)
return this
}

/**
* Handle back btn action when the back button is pressed
*
*
@param onAction, [Unit]
*
@return [AppToolbar]
*/
fun onBackPressed(onAction: () -> Unit): AppToolbar {
binding?.ivToolbarBack?.setOnClickListener {
onAction.invoke()
}
return this
}
}

Note:

  1. AppToolbar constructor is private
  2. Have to use the builder provided by AppToolbar to initialize the AppToolbar
  3. Have to provide the binding reference for your custom toolbar layout
  4. AppToolbar provide some API to handle action or manipulate the Custom Toolbar
  5. You can add your additional API based on your requirement

Now: Lets take a look at the usages of the API

Include your custom toolbar at the parent activity for your fragments, provide a specifc id for the included layout.

Note: We are using DataBinding for this project. The API class is designed to accept only the *Binding refernce for the custom toolbar layout

To initialize the AppToolbar, use the Builder class to provide the included layout id from the *activity.xml and get an initialized reference of the AppToolbar.

Note:

  1. You have to pass the id of the included layout (*Binding reference)
  2. If you not pass the reference, AppToolbar will throw an Exception

Now, let’s take a look at the “How to consume the API from Several Fragments”

We have 3 fragments called HomeFragment, NewUploadFragment, AccountFramgent

On your specific fragment class, consume the API on onResume().

Note:

  1. Cast the activity reference to the specific activity
  2. Use the API to handle actions or manipulate the toolbar
  3. AppToolbar onBackPressed() act as an callback. Notify the button pressed action through the Kotlin’s Higher Order Function without actually creating an Interface to use as a callback.

That’s all for Today. Let me know for any kind of discussion or update or fix.

Connect with me on LinkedIn: https://www.linkedin.com/in/rommansabbir/

Follow me on GitHub: https://github.com/rommansabbir/

For Android, Backend Application Development purpose email me at: rommansabbir@gmail.com or Visit my portfolio: www.rommansabbir.com

--

--

Romman Sabbir
Romman Sabbir

Written by Romman Sabbir

Senior Android Engineer / Electronic Music Producer

Responses (1)