Android: Custom Toolbar
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:
- Root ConstraintLayout id is `toolbar_root_layout`
- Card View height is `56dp`, standard size for Toolbar
- 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:
- AppToolbar constructor is private
- Have to use the builder provided by AppToolbar to initialize the AppToolbar
- Have to provide the binding reference for your custom toolbar layout
- AppToolbar provide some API to handle action or manipulate the Custom Toolbar
- 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:
- You have to pass the id of the included layout (*Binding reference)
- 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:
- Cast the activity reference to the specific activity
- Use the API to handle actions or manipulate the toolbar
- 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