Awesome
SnackProgressBar
Enhanced Snackbar with ProgressBar for Android.
Important
Please do not use v6.0 and v6.1 due to issue #20 and #23.
Versions
- v6.4.0 added 'Rounded Corner Background' as per latest Material Design! To use it, call
SnackProgressBarManager.useRoundedCornerBackground(true)
. It isfalse
by default. - v6.1.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 inOnDestroy
to prevent memory leak.
- SnackProgressBarLayout is now public, so you can directly edit the layout in
- 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
. - v3.4 is using Snackbar types of
TYPE_ACTION
,TYPE_MESSAGE
,TYPE_DETERMINATE
,TYPE_INDETERMINATE
.
Features
- Two types of ProgressBar (TYPE_HORIZONTAL and TYPE_CIRULAR) are available (see image below). It can also be used as a normal SnackBar.
- Supports multi-lines of message.
- Supports long action text by moving it to next line as per Material Design.
- Supports swipe to dimiss behaviour even without providing CoordinatorLayout. (Or you can remove this behaviour for CoordinatorLayout)
- Additional views can be added to animate with the SnackProgressBar.
- Provides OverlayLayout to prevent user input.
- Provides a queue system.
- Icon can be added.
- Supports bundle in SnackProgressBar to carry information.
- Supports changing element color and text size.
NOTE: This library is still following the old Material Design Specifications.
<img src="https://i.imgur.com/AriEeV2.png" width="500">Watch the demo video at https://youtu.be/dbawFbr6iPk.
Getting Started
You must have colorAccent
declared in colors.xml
file in your res
folder. This library needs this value to apply proper styling to SnackProgressBar. Example:
res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorAccent">@android:color/holo_red_dark</color>
</resources>
SnackProgressBarManager
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?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_demo)
val floatingActionButton = findViewById<View>(R.id.fab)
snackProgressBarManager
// (Optional) Set the view which will animate with SnackProgressBar e.g. FAB when CoordinatorLayout is not used
.setViewToMove(floatingActionButton)
// (Optional) Change progressBar color, default = R.color.colorAccent
.setProgressBarColor(R.color.colorAccent)
// (Optional) Change background color, default = BACKGROUND_COLOR_DEFAULT (#FF323232)
.setBackgroundColor(SnackProgressBarManager.BACKGROUND_COLOR_DEFAULT)
// (Optional) Change text size, default = 14sp
.setTextSize(14f)
// (Optional) Set max lines, default = 2
.setMessageMaxLines(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
}
})
}
SnackProgressBar
Create a SnackProgressBar by calling the following examples.
// TYPE_NORMAL
val normalType =
SnackProgressBar(SnackProgressBar.TYPE_NORMAL, "TYPE_NORMAL - $queue")
// (Optional) allow user input, default = FALSE
.setAllowUserInput(true)
// (Optional) allow user swipe to dismiss, default = FALSE
.setSwipeToDismiss(true)
// (Optional) set icon
.setIconResource(R.mipmap.ic_launcher)
// Create a bundle and attach to snackProgressBar which can be retrieved via OnDisplayListener
val bundle = Bundle()
bundle.putInt("queue", queue)
normalType.putBundle(bundle)
// TYPE_NORMAL with action
val normalTypeWithAction =
SnackProgressBar(
SnackProgressBar.TYPE_NORMAL,
"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()
}
})
// TYPE_HORIZONTAL
val horizontalType =
SnackProgressBar(SnackProgressBar.TYPE_HORIZONTAL, "TYPE_HORIZONTAL - Loading...")
// (Optional) Set the type of progressBar, default = FALSE
.setIsIndeterminate(false)
// (Optional) Set max progress, default = 100
.setProgressMax(100)
// (Optional) Show percentage, default = FALSE
.setShowProgressPercentage(true)
// 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...")
.setIsIndeterminate(true)
.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
Show the SnackProgressBar by calling:
// LENGTH_SHORT, LENGTH_LONG, LENGTH_INDEFINITE or other positive millis can be used
snackProgressBarManager.show(snackProgressBar, SnackProgressBarManager.LENGTH_LONG)
You can include an onDisplayId
when calling show()
.
val onDisplayId = 100
snackProgressBarManager.show(snackProgressBar, 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.show(storeId, SnackProgressBarManager.LENGTH_LONG)
Calling show() will put the SnackProgressBar into a queue. It will be shown after other queued SnackProgressBars.
Note: Starting v6.2.0, if LENGTH_INDEFINITE is specified for the queued SnackProgressBar, adding a new SnackProgressBar into the queue will cause the previous SnackProgressBar to be dismissed after showing completely. Prior to that, the SnackProgressBar will be dismissed after LENGTH_SHORT and then show the new SnackProgressBar, but this is counter-intuitive and causes issue #26 and #28.
Update
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
snackProgressBarManager.updateTo(snackProgressBar)
Dismiss
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.
Disable
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.
JavaDoc
For further information, see https://tingyik90.github.io/snackprogressbar/lib/.
Download
In the project Gradle:
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
In the app Gradle:
dependencies {
implementation 'com.github.tingyik90:snackprogressbar:version'
}
License
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
http://www.apache.org/licenses/LICENSE-2.0
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.