Simple circular progress indicator
Tags: android, kotlin, vectordrawable, animation
Published: 2020-02-02 00:17:06

## Simple Circular ProgressView Animation

When it comes to UI and loading data, there is always a requirement to fetch the data we want to load in the UI. It is either from fetching from remote,  or local database. And as we all know, fetching data adds latency more often than not, leaves us with a blank screen until the data is ready. 

The challenge now is to actually keep the user engaged and provide some context while the data is loading. Most of the times, our first go-to way of indicating that `the app is doing something` is to throw a `ProgressView` with a default timeout of `15` seconds or so. In most cases this does the job but this shouldn't always be our go-to way. While there are several ways and recommendations of handling this with more contextual loading screens, `placeholders` or Facebook's `ShimmerLayout` , one simple way of adding some context to the progress is to display a ProgressView that `actually` shows progress, rather than a `continuously` spinning for 15 seconds. 

Let me introduce a simple way that I implemented. This approach is to display an `animated` circular progress view. 

It has following pieces:

* Vector drawable for the circle
* Animated-vector drawable for the animation
* Animation trigger
* Actual Animation

#### Vector drawable for the circle

```xml
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="28dp"
    android:height="28dp"
    android:viewportWidth="28"
    android:viewportHeight="28"
    >
  <path
      android:name="circle"
      android:pathData="M14,1.5C7.1,1.5 1.5,7.1 1.5,14C1.5,20.9 7.1,26.5 14,26.5C20.9,26.5   26.5,20.9 26.5,14C26.5,7.1 20.9,1.5 14,1.5Z"
      android:strokeWidth="3"
      android:fillColor="#00000000"
      android:strokeColor="#88D445"
      android:fillType="evenOdd"
      />
</vector>
```

#### Animated-vector drawable for the animation

```xml
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:drawable="@drawable/circle"
    tools:targetApi="21"
    >
  <target
      android:name="circle"
      android:animation="@animator/circle_animation"
      />
</animated-vector>
```

#### Animation trigger

From ViewModel

```kotlin
val animationStart = MutableLiveData<Int>()
```

From Fragment

```kotlin
private fun observeAnimationStart() {
    viewModel.animationStart.observe {
      activity?.let { act ->
        val drawableCircle: AnimatedVectorDrawableCompat? =
          AnimatedVectorDrawableCompat.create(act as Context, R.drawable.animated_circle)
        animateProgressView(drawableCircle)
      }
    }
}
```



### Actual Animation

```kotlin
private fun animateProgressView(drawable: AnimatedVectorDrawableCompat) {
    binding.animationImageView.background = drawable

    val animatable: Animatable2Compat = drawable
    animatable.registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
      override fun onAnimationEnd(drawable: Drawable?) {
        binding.animationImageView.background = null
      }
    })
    animatable.start()
}
```

This implementation was done for a simple `MVVM` architecture. The `ViewModel` sould expose the ProgressView `show/hide` state via. `LiveData` or `SingleLiveEvent` which is `observed` by the corresponding `Fragment`. Now, this  fragment is responsile for starting and ending the animation, or when the aimation is done, just assign `null` for the drawable.

Please refer to the above code sample to get more information on the implementation. Also, please feel free to add comments if you have come across better ways of implementing this.

Note: Due to backward campatibility, I am using `AminatedVectorDrawableCompat` and `Animatable2Compat` for drawable. Also, there is no timing. It is simply drawing the path. So, this wouldn't be ideal for long running progress view.