Android Show ProgressBar Below Toolbar/AppBar

Nov 27, 2019

Layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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=".view.support.GalleryActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

            <ProgressBar
                android:id="@+id/progressBar"
                android:layout_marginTop="-7dp"
                android:layout_marginBottom="-7dp"
                android:max="100"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                style="?android:attr/progressBarStyleHorizontal"
                android:visibility="gone"
                />

    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/main_content" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

I am using LiveData to update ProgressBar, which support 2 mode

  • Busy Mode (horizontal animation)
  • Progress Mode (horizontal progress)
class MainActivity : AppCompatActivity() {    private val viewModel by viewModels<MainViewModel>()    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.main)        setSupportActionBar(toolbar)        init()    }    private fun init() {        viewModel.busyEvent.observe(this, Observer { event ->            event.getIfPending()?.also { show ->                if (show) {                    // prevent restart bug with progress animation                    progressBar.progress = 0                    progressBar.isVisible = true                    progressBar.isIndeterminate = true                }                else {                    progressBar.isGone = true                    progressBar.isIndeterminate = false                    // prevent restart bug with progress animation                    progressBar.progress = 0                }            }        })        viewModel.progressEvent.observe(this, Observer { event ->            event.getIfPending()?.also { value ->                progressBar.isVisible = true                progressBar.isIndeterminate = false                val progress = (value * progressBar.max).toInt()                /*                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {                    // progressBar.progress = progress                    progressBar.setProgress(progress, true)                }                */                val animation: ObjectAnimator =                    ObjectAnimator.ofInt(progressBar, "progress", progressBar.progress, progress)                animation.duration = 500                animation.interpolator = DecelerateInterpolator()                animation.start()            }        })    }    fun testBusy() {        viewModel.busyEvent.value = Event(true)        lifecycleScope.launch {            delay(5000)            viewModel.busyEvent.value = Event(false)        }    }    fun testProgress() {        viewModel.busyEvent.value = Event(true)        lifecycleScope.launch {            repeat(10) {                delay(1000)                viewModel.progressEvent.value = Event((it+1)/10.0)            }            viewModel.busyEvent.value = Event(false)        }    }}

NOTE: Get ViewModel via ktx

ViewModel

class MainViewModel(application: Application) : AndroidViewModel(application) {    internal val busyEvent = MutableLiveData<Event<Boolean>>()    internal val progressEvent = MutableLiveData<Event<Double>>()}

NOTE: Android LiveData: Handle UI Event With Event Wrapper

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.