Dauris Little
all
  • About
  • Dauris’s Portfolio
  • Blogging Lyf
  • Contact
© 2016 Dauris Little. All rights reserved.
  • Home
  • Blog
  • Programming Languages
  • Android
  • Creating Advance Custom Snackbar w/ Kotlin
November 12, 2025

BLOG & Gossip

Avatar photo
Dauris
Monday, 28 June 2021 / Published in Android, Kotlin, Programming Languages, Tutorial

Creating Advance Custom Snackbar w/ Kotlin

Ask 100 different developers about what they find most exciting about android development and you will get as many different responses. Personally, I find the customization of the various framework and design libraries. Consider it as such if there is something that doesn’t fit your needs within the development process that as a developer we create custom views without any issues. Within this post, we will be working on a custom Snackbar.

What is a Snackbar? Well simply enough a Snackbars provide lightweight feedback about an operation. They show a brief message at the bottom of the screen on mobile and lower left on larger devices. Snackbars appear above all other elements on screen and only one can be displayed at a time.

Though the Snackbar by default has a few customizable features, consider the fact that the default features may not match the application style. Fortunately, we can easily create a custom Snackbar by implementing just a few classes.  If you are unfamiliar with what a Snackbar is please review my previous post regarding the library. Be aware that it may be a little confusing at glance but fear not we will review it the most important part that is to highlight which are:

  • BottomTransientBottomBar which is the parent view
    •  ContentViewCallback
  • make() a factory method
    • find the parent view, inflate the custom view, and set additional properties 
  • customizable method

Custom View

It is assumed that you have already created/opened your current project within your IDE. Now we create a custom view that will be displayed at the bottom of the screen when called. This design will be the simplest form which contains an image and static message.

class CustomSnackbarView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ConstraintLayout (context, attrs, defStyleAttr) {

    private val customImg : AppCompatImageView

    init {
        View.inflate(context, R.layout.view_custom_snackbar, this)
        clipToPadding = false
        this.customImg = findViewById(R.id.img_snack)
    }
}

this is accompanied by the following layout XML

<?xml version="1.0" encoding="utf-8"?>
<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">

    <androidx.appcompat.widget.AppCompatImageView
        android:layout_width="173dp"
        android:layout_height="173dp"
        android:id="@+id/img_snack"
        android:scaleType="centerInside"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:srcCompat="@drawable/pokeball" />

    <androidx.appcompat.widget.AppCompatTextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:id="@+id/tv_snack"
        android:gravity="center"
        android:padding="16dp"
        android:text="You have caught another sir!"
        android:textColor="#28140c"
        android:background="@drawable/custom_snackbar_bg"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="@+id/img_snack"
        app:layout_constraintLeft_toRightOf="@+id/img_snack"
        app:layout_constraintStart_toEndOf="@+id/img_snack"
        app:layout_constraintTop_toTopOf="@+id/img_snack"
        app:layout_constraintVertical_bias="0.75" />
</merge>

Implementation of Custom View

Now the objective is to implement ContentViewCallback. The interface objective is to notify when the Snackbar starts appearing  and dismissing using animateContentIn() and animateContentOut()

class CustomSnackbarView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : ConstraintLayout (context, attrs, defStyleAttr), ContentViewCallback {

    private val customImg : AppCompatImageView

    init {
        View.inflate(context, R.layout.view_custom_snackbar, this)
        clipToPadding = false
        this.customImg = findViewById(R.id.img_snack)
    }

    override fun animateContentIn(delay: Int, duration: Int) {
        val scaleX = ObjectAnimator.ofFloat(customImg, View.SCALE_X, 0f, 1f)
        val scaleY = ObjectAnimator.ofFloat(customImg, View.SCALE_Y, 0f, 1f)
        AnimatorSet().apply {
            interpolator = OvershootInterpolator()
            setDuration(500)
            playTogether(scaleX,scaleY)
        }.start()

    }

    override fun animateContentOut(delay: Int, duration: Int) {
        TODO("Not yet implemented")
    }

}

Take note that there is a simple scale animation as the Snackbar appears. Now setting the clipToPadding to false is important to avoid the image from clipping because of OvershootInterpolator.

Extending BaseTransientBottomBar

We are now at the point to create an equivalent class for the Snackbar.

The custom Snackbar constructor accepts two params: one for the parent view and another for the custom view that supports the implementation of ContentViewCallback.

class CustomSnackbar(parent: ViewGroup, content: CustomSnackbarView) : BaseTransientBottomBar<CustomSnackbar>(parent, content, content) {

}

Now to implement the entry point method make(). As stated earlier in this post, there are three things to accomplish:

  • There is no reason to attempt and recreate the wheel so we will borrow the logic from the Snackbar’s source code
internal fun View?.findParent(): ViewGroup? {

    var view = this
    var fallback: ViewGroup? = null

    do {
        if (view is CoordinatorLayout) {
            //the Coordinator layout has been found
            return view
        } else if (view is FrameLayout) {
            if (view.id == android.R.id.content) {
                //coordinator layout not found so we need to use the appropriate hierarchy
                return view
            } else {
                //if no view assign the fallback
                fallback = view
            }
        }

        if (view != null) {
            //will continue to search for the view
            val parent = view.parent
            view = if (parent is View) parent else null
        }
    } while (view != null)

    return fallback
}
  • Inflate the custom view
    • inflating a custom view is best done by using the XML layout
<?xml version="1.0" encoding="utf-8"?>
<com.programmingninja.advancesnackbar.snackbar.CustomSnackbarView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp" />
  • Build and correct errors
class CustomSnackbar(parent: ViewGroup, content: CustomSnackbarView) : BaseTransientBottomBar<CustomSnackbar>(parent, content, content) {

    companion object {
        fun make(view: View) : CustomSnackbar{

            //set parent for this view
            val parent = view.findParent() ?: throw IllegalArgumentException("No suitable parent found from the correct view. Please correct.")

            //custom view inflated
            val customView = LayoutInflater.from(view.context).inflate(R.layout.activity_snackbar, parent, false) as CustomSnackbarView

            //creation and return this new snackbar
            return CustomSnackbar(parent, customView)
        }

    }
}

If we attempt to run the code, you will notice that there is a gray background and padding. Why is this? This is because the BaseBottomTransientBar implementation is wrapped with the SnackbarBasrLayout. The workaround for this issue is simple enough by adding an init() block

init {
        getView().setBackgroundColor(ContextCompat.getColor(view.context, android.R.color.transparent))
        getView().setPadding(0,0,0,0)
}

Wrapping it altogether

Modify the MainActivity with the following

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<View>(R.id.btn_catch_em).setOnClickListener {
            CustomSnackbar.make(it).show()
        }
    }
}

Now we need to modify the main activity layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.AppCompatButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btn_catch_em"
        android:layout_margin="8dp"
        android:text="Throw Poke Ball"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

  • Tweet
Tagged under: android, android development, androidx, kotlin, Mobile Development

What you can read next

Android Rating: In-App Review API
Shimmering in Android
allowBackup: Android’s Attributes

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Categories

Recent Posts

  • Gesture Controls for Android w/Kotlin

    Incorporating Gesture controls in your android ...
  • Android Rating: In-App Review API

    An app rating and reviews are crucial if you wa...
  • QR Reader in Android w/ Kotlin

    Turn your phone's camera into a QR scanner...
  • Swift Has Tuple

    Swift provides us with a type called Tuple whic...
  • “Structs vs Classes” and using them

    This is because it plays a significant role in ...

Recent Comments

  • Homepage on Integrating Google’s reCAPTCHA w/Android
  • Cleora Weideman on Integrating Google’s reCAPTCHA w/Android
  • alpha femme keto Reviews on Integrating Google’s reCAPTCHA w/Android
  • best skin care products reviews on Integrating Google’s reCAPTCHA w/Android
  • Robyn on Integrating Google’s reCAPTCHA w/Android

Archives

  • January 2022
  • December 2021
  • September 2021
  • June 2021
  • May 2021
  • April 2021
  • March 2021
  • February 2021
  • January 2021
  • December 2020
  • October 2020
  • August 2020
  • July 2020
  • May 2020
  • March 2020
  • February 2020
  • December 2019
  • October 2019
  • September 2019
  • May 2019
  • March 2019
  • February 2019
  • January 2019
  • August 2018
  • April 2018
  • August 2017
  • November 2016
  • August 2016

Categories

  • .NET & .NET Core
  • Active Directory
  • Android
  • API
  • bitcoin
  • blog
  • C#
  • Development
  • E-Commerce
  • HTML5
  • iOS
  • Java
  • Javascript
  • Kotlin
  • Language
  • Like I Am Five
  • Mobile Development
  • New Web Site
  • Programming Languages
  • Swift
  • Tutorial
  • Uncategorized
  • Web Application Development
  • Windows AD

Meta

  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org

© 2015. All rights reserved. Buy Kallyas Theme.

TOP
This site uses tracking cookies to personalize content and ads. AcceptLearn More