Replace ProgressDialog with a progress button in your app

Anton Hadutski
ProAndroidDev
Published in
3 min readApr 28, 2019

--

Progress Button is one of the options to show non-blocking progress in the app that Google introduced in its Material Guidelines. Unfortunately, Google doesn’t provide the out of box implementation, but we can see how to implement it using existing components and moreover how to add it to your existing app without layout changes. Stay on board!

Our goal would look like that:

Well, option 1 would be to add ProgressBar to our layout, but it’s not always convenient and easy. Default buttons have some predefined paddings, and it’s not easy to align ProgressBar on the button center. What if we want to add a text later like that? Should we change the layout again on each screen?

Option 2 would be to use 3rd party components like this. One of the main disadvantages of such an approach is you lose some part of the flexibility, and for example, you can’t take advantage of the new MaterialButton by Google. It also doesn’t follow guidelines.

Option 3: We already have a solution to show progress using drawable provided by Android — AnimationDrawable. Luckily we have a ready to use progress drawable in a support-v4 package — CircularProgressDrawable. We also have a solution to show drawable along with text — SpannableString + DynamicDrawableSpan. So then just a few lines and…

It doesn’t work as expected.

  1. The animation is freezing
  2. The drawable is not aligned with the text baseline
  3. There is no padding between text and progress

Let’s try to solve the first problem. The animation is freezing because our button doesn’t know when to redraw its state. DynamicDrawableSpan doesn’t trigger button redraw by default. That means we have to do it manually. We can subscribe to AnimationDrawable animation updates and call button.invalidate() to force button call draw while the animation is active. Now animation works fine:

Now let’s align the drawable properly. To do so, we can extend ImageSpan and override getSize and draw methods. For a better understanding of what each font metrics means you can refer to great explanation by Orhan Obut.

and use new Spannable class

val drawableSpan = CustomDrawableSpan(progressDrawable, marginStart = 20)

Let’s check the result:

You could see that “text to progress” transition is not smooth enough. We can fix it by using ObjectAnimator. I’m not going to cover this topic here though, but you can get the idea from here.

I already prepared a “ready to use” library called “ProgressButton” for you. So you don’t need to handle view lifecycle and create all this code from scratch. It also provides smooth text change animations out of the box.

That’s all guys. Thanks for your time. You can read my next article here. Please press “Clap” if you find this useful so it would encourage me for the next post :)

--

--