Creating a Custom Loading Spinner for Android š¤
Recently at Krugo, I was implementing a custom loading animation. I donāt usually write about work things, but this one was different.
First, the Setup
First I implemented this BehaviorSubject in my Dependency Injection:
var progressBar: BehaviorSubject<Boolean> = BehaviorSubject.createDefault(false)
fun setProgressBar(value: Boolean) {
progressBar.onNext(value)
}
And subscribed to it from the MainActivity:
Injector.progressBar.subscribeBy(
onNext = {
if (it) {
this.mainProgress.visibility = View.VISIBLE
} else {
this.mainProgress.visibility = View.GONE
}
},onError = {})
.addTo(compositeDisposable)
These together allow me to toggle the ProgressBar view (that was set up in activity_main) simply by calling Injector.setProgressBar(true)
and Injector.setProgressBar(false)
.
Second, the Animation
Hereās the fun part. I used Shape Shifter to make the animation, this is what I made:
Shape Shifter allows you to export the animation as an animated-vector
, made just for Android.
I found that breaking that animated-vector
into four separate files worked best. The first is the main file, make sure your ProgressBar uses this.
<animated-vector
android:drawable="@drawable/your_vector_file">
<target
android:name="group1"
android:animation="@anim/your_first_animation_file" />
<target
android:name="group2"
android:animation="@anim/your_second_animation_file" />
</animated-vector>
The vector file, taken from the <vector>
section of the animated-vector
:
<vector android:name="vector"
android:viewportWidth="1024"
android:viewportHeight="1024">
<group ... />
<group ... />
</vector>
And the two animation files taken from the <target>
sections and placed under res/anim/
. Theyāll look like this:
<set>
<objectAnimator ... />
<objectAnimator ... />
<objectAnimator ... />
<objectAnimator ... />
</set>
Third, Making it Work
This was all great, but it didnāt exactly work. The animation wouldnāt repeat itself after it completed. Took a while but finally got it working by doing the following:
Change ProgressBar
to ImageView
<ImageView
android:contentDescription="@string/loading"
android:id="@+id/progress_bar"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center" />
Initialize the animation including registerAnimationCallback
to force the looping of the animation.
val avd = AnimatedVectorDrawableCompat.create(applicationContext,
R.drawable.your_vector_file)
findViewById<ImageView>(R.id.progress_bar).apply {
setImageDrawable(avd)
}
avd?.registerAnimationCallback(obj:Animatable2Compat.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable?) {
avd.start()
}
})
To top it off, I added start()
and stop()
to my subscribeBy
method just to be nice:
Injector.progressBar.subscribeBy(
onNext = {
if (it) {
this.mainProgress.visibility = View.VISIBLE
avd?.start()
} else {
this.mainProgress.visibility = View.GONE
avd?.stop()
}
},onError = {})
.addTo(compositeDisposable)
This last step took me a while to figure out but I finally got it thanks to this article from the Android Developers blog:
Overall I loved the chance to work on some animation, I think itās just going to become a bigger thing in 2019 and more of a priority for me to learn!
Krugo Travel
Quick shoutout to the company Iām working for, Krugo. Iām working on getting the Android app up and running hence why I was doing this little animation in Android!
Have you ever been frustrated trying to plan a trip with a group of people? Maybe a bachelor party, family vacation or trip with the girls? If so, youāre not alone.
And weāve made it our mission to help.
Krugo helps groups of friends collaboratively plan trips by finding events, buying tickets and getting a place to stay. Canāt wait to take my own Krugo soon š
Check āem out on Medium or get the app for iOS. Android coming soon!