Skip to content
Enhanced Snackbar with ProgressBar for Android.
Branch: master
Clone or download
tingyik90 - Added @keep annotation for companion object
- Correct casting of parent view in animateContentIn
- Added fourth LinearLayout constructor
Latest commit c4a1fb7 May 11, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
.idea v3.0 Dec 2, 2017
app - Update casting of layout params. May 11, 2019
docs/lib - Updates May 8, 2019
gradle/wrapper - Update gradle. May 1, 2019
lib - Added @keep annotation for companion object May 11, 2019
.gitignore Git ignore. Apr 16, 2018
LICENSE.txt Update LICENSE.txt May 9, 2019 Update May 9, 2019
build.gradle - Update gradle. May 1, 2019 - Disable R8 May 9, 2019
gradlew Initial commit May 24, 2017
gradlew.bat Initial commit May 24, 2017
settings.gradle Initial commit May 24, 2017


Enhanced Snackbar with ProgressBar for Android.


Please do not use v6.0. It is a broken compilation due to new R8 shrinker. minifyEnabled has been turned to false since v6.1.


  • v6.1 does not break migration from v5.0. Added the following features:
    • SnackProgressBarLayout is now public, so you can directly edit the layout in OnDisplayListener.onLayoutInflated.
    • WeakReference is now used for views to prevent memory leak.
    • LifeCycle Architecture is used to call SnackProgressBarManager.disable() automatically in OnDestroy to prevent memory leak.
  • v5.0 is a migration to androidx from v4.1. There is no change in all methods. Only use this if you have migrated.
  • v4.1 is a huge leap from v3.4 and offers much better flexibility. Snackbar types changed to TYPE_NORMAL, TYPE_HORIZONTAL, TYPE_CIRCULAR.


  1. Two types of ProgressBar (TYPE_HORIZONTAL and TYPE_CIRULAR) are available (see image below). It can also be used as a normal SnackBar.
  2. Supports multi-lines of message.
  3. Supports long action text by moving it to next line as per Material Design.
  4. Supports swipe to dimiss behaviour even without providing CoordinatorLayout. (Or you can remove this behaviour for CoordinatorLayout)
  5. Additional views can be added to animate with the SnackProgressBar.
  6. Provides OverlayLayout to prevent user input.
  7. Provides a queue system.
  8. Icon can be added.
  9. Supports bundle in SnackProgressBar to carry information.
  10. Supports changing element color and text size.

NOTE: This library is still following the old Material Design Specifications.

Watch the demo video at

Getting Started


Start by creating an instance of SnackProgressBarManager in your activity. If possible, the root view of the activity should be provided and can be any type of layout. Starting v6.0, you can provide a LifecycleOwner of an activity / fragment. This will call SnackProgressBarManager.disable() in OnDestroy to prevent memory leak.

private val snackProgressBarManager by lazy { SnackProgressBarManager(mainLayout, lifecycleOwner = this) }

override fun onCreate(savedInstanceState: Bundle?) {
    val floatingActionButton = findViewById<View>(
        // (Optional) Set the view which will animate with SnackProgressBar e.g. FAB when CoordinatorLayout is not used
        // (Optional) Change progressBar color, default = R.color.colorAccent
        // (Optional) Change background color, default = BACKGROUND_COLOR_DEFAULT (#FF323232)
        // (Optional) Change text size, default = 14sp
        // (Optional) Set max lines, default = 2
        // (Optional) Register onDisplayListener
        .setOnDisplayListener(object : SnackProgressBarManager.OnDisplayListener {
            override fun onLayoutInflated(
                snackProgressBarLayout: SnackProgressBarLayout,
                overlayLayout: FrameLayout,
                snackProgressBar: SnackProgressBar,
                onDisplayId: Int
            ) {
                // In v6.0, both snackProgressBarLayout and overlayLayout are exposed.
                // You can edit them directly without reflection.

            override fun onShown(snackProgressBar: SnackProgressBar, onDisplayId: Int) {
                // We have assigned onDisplayId = 5000 for normalType SnackProgressBar
                if (onDisplayId == 5000) {
                    // You can retrieve the attached information here
                    val bundle = snackProgressBar.getBundle()
                    if (bundle != null) {
                        val queueNo = bundle.getInt("queue")
                        val toast = "Showing queue $queueNo!"
                        Toast.makeText(applicationContext, toast, Toast.LENGTH_SHORT).show()

            override fun onDismissed(snackProgressBar: SnackProgressBar, onDisplayId: Int) {
                // Do something


Create a SnackProgressBar by calling the following examples.

val normalType =
    SnackProgressBar(SnackProgressBar.TYPE_NORMAL, "TYPE_NORMAL - $queue")
        // (Optional) allow user input, default = FALSE
        // (Optional) allow user swipe to dismiss, default = FALSE
        // (Optional) set icon
// Create a bundle and attach to snackProgressBar which can be retrieved via OnDisplayListener
val bundle = Bundle()
bundle.putInt("queue", queue)

// TYPE_NORMAL with action
val normalTypeWithAction =
        "TYPE_NORMAL - If the message and action are too long, a higher layout is used."
    ).setAction("LONG ACTION TEXT", object : SnackProgressBar.OnActionClickListener {
        // (Required) Set action button
        override fun onActionClick() {
            Toast.makeText(applicationContext, "Action Clicked!", Toast.LENGTH_SHORT).show()

val horizontalType =
    SnackProgressBar(SnackProgressBar.TYPE_HORIZONTAL, "TYPE_HORIZONTAL - Loading...")
        // (Optional) Set the type of progressBar, default = FALSE
        // (Optional) Set max progress, default = 100
        // (Optional) Show percentage, default = FALSE

// TYPE_CIRCULAR with action
// This type of layout is not recommended, simply because it is ugly.
val circularTypeWithAction =
    SnackProgressBar(SnackProgressBar.TYPE_CIRCULAR, "TYPE_CIRCULAR - Loading...")
        .setAction("DISMISS", object : SnackProgressBar.OnActionClickListener {
            override fun onActionClick() {
                Toast.makeText(applicationContext, "Action Clicked!", Toast.LENGTH_SHORT).show()

Note that action can be inserted in every type of SnackProgressBar.


Show the SnackProgressBar by calling:

// LENGTH_SHORT, LENGTH_LONG, LENGTH_INDEFINITE or other positive millis can be used, SnackProgressBarManager.LENGTH_LONG)

You can include an onDisplayId when calling show().

val onDisplayId = 100, SnackProgressBarManager.LENGTH_LONG, onDisplayId)

Or you can add the SnackProgressBar into memory and call it later.

// It is stored in HashMap, so storeId must be unique for each SnackProgressBar, else it will be overwritten
val storeId = 100
snackProgressBarManager.put(snackProgressBar, storeId), SnackProgressBarManager.LENGTH_LONG)

Calling show() will put the SnackProgressBar into a queue, which will be shown after those in queue before it has been dismissed (by user action or set showDuration).

Note: If LENGTH_INDEFINITE is specified for the queued SnackProgressBar, adding a new SnackProgressBar into the queue will cause the previous SnackProgressBar to use LENGTH_SHORT instead, dismissed and then show the new SnackProgressBar.


Calling show() will always animate the hiding and showing of SnackProgressBar between queue. Use updateTo() instead to modify the displayed SnackProgressBar without animation. To modify the currently showing SnackProgressBar:

// Get the currently showing indeterminateType and change the message
val snackProgressBar = snackProgressBarManager.getLastShown()
snackProgressBar.setMessage("new message")
// Calling updateTo() will not hide and show again the SnackProgressBar


Call snackProgressBarManager.dismiss() to dismiss the currently showing SnackProgressBar. The next SnackProgressBar in queue will be shown. Call snackProgressBarManager.dismissAll() to dismiss the currently showing SnackProgressBar and clear all other SnackProgressBars in queue.

Set Progress

Call snackProgressBarManager.setProgress() to set the progress of ProgressBar.


IMPORTANT: To avoid memory leak, call SnackProgressBarManager.disable() in onDestroy manually. Else, provide a LifecycleOwner in the constructor of SnackProgressBarManager to automatically call this method.


For further information, see

See demo at


In the project Gradle:

allprojects {
    repositories {
        maven { url "" }

In the app Gradle:

dependencies {
    implementation 'com.github.tingyik90:snackprogressbar:version'


Copyright 2017-2019 Saw Ting Yik

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

You can’t perform that action at this time.