Skip to content

Instantly share code, notes, and snippets.

@DarkionAvey
Last active April 28, 2023 12:26
Show Gist options
  • Save DarkionAvey/71cc8d31b5f4447abe598753e63e1664 to your computer and use it in GitHub Desktop.
Save DarkionAvey/71cc8d31b5f4447abe598753e63e1664 to your computer and use it in GitHub Desktop.
iOS-like spinner as an animated vector drawable for Android without the need of custom classes, or worse, gifs. Use support library to get it to work on older devices. To change color, simply change fillColor but not the alpha. You have to register a callback to make it repeat, because android doesn't allow animationset to repeat
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector
android:name="vector"
android:width="20dp"
android:height="20dp"
android:viewportWidth="60"
android:viewportHeight="60">
<path
android:name="path_1"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:pathData="M 33 12 C 33 13.7 31.7 15 30 15 C 28.3 15 27 13.7 27 12 L 27 3 C 27 1.3 28.3 0 30 0 C 31.7 0 33 1.3 33 3 L 33 12 Z M 33 48 C 33 46.3 31.7 45 30 45 C 28.3 45 27 46.3 27 48 L 27 57 C 27 58.7 28.3 60 30 60 C 31.7 60 33 58.7 33 57 L 33 48 Z M 3 27 C 1.3 27 0 28.3 0 30 C 0 31.7 1.3 33 3 33 L 12 33 C 13.7 33 15 31.7 15 30 C 15 28.3 13.7 27 12 27 L 3 27 Z M 48 27 C 46.3 27 45 28.3 45 30 C 45 31.7 46.3 33 48 33 L 57 33 C 58.7 33 60 31.7 60 30 C 60 28.3 58.7 27 57 27 L 48 27 Z M 5.1 40.9 C 3.7 41.8 3.2 43.6 4 45 C 4.8 46.4 6.7 46.9 8.1 46.1 L 15.9 41.6 C 17.3 40.8 17.8 38.9 17 37.5 C 16.2 36.1 14.3 35.6 12.9 36.4 L 5.1 40.9 Z M 44.1 18.4 C 42.7 19.2 42.2 21.1 43 22.5 C 43.8 23.9 45.7 24.4 47.1 23.6 L 54.9 19.1 C 56.3 18.3 56.8 16.4 56 15 C 55.2 13.6 53.3 13.1 51.9 13.9 L 44.1 18.4 Z M 40.9 54.9 C 41.7 56.3 43.6 56.8 45 56 C 46.4 55.2 46.9 53.3 46.1 51.9 L 41.6 44.1 C 40.8 42.7 38.9 42.2 37.5 43 C 36.1 43.8 35.6 45.7 36.4 47.1 L 40.9 54.9 Z M 18.4 15.9 C 19.2 17.3 21.1 17.8 22.5 17 C 23.9 16.2 24.4 14.3 23.6 12.9 L 19.1 5.1 C 18.3 3.7 16.4 3.2 15 4 C 13.6 4.8 13.1 6.7 13.9 8.1 L 18.4 15.9 Z M 13.9 51.9 C 13.1 53.3 13.6 55.2 15 56 C 16.4 56.8 18.3 56.3 19.1 54.9 L 23.6 47.1 C 24.4 45.7 23.9 43.8 22.5 43 C 21.1 42.2 19.2 42.7 18.4 44.1 L 13.9 51.9 Z M 36.4 12.9 C 35.6 14.3 36.1 16.2 37.5 17 C 38.9 17.8 40.8 17.3 41.6 15.9 L 46.1 8.1 C 46.9 6.7 46.4 4.8 45 4 C 43.6 3.2 41.7 3.7 40.9 5.1 L 36.4 12.9 Z M 51.9 46.1 C 53.3 46.9 55.2 46.4 56 45 C 56.8 43.6 56.3 41.7 54.9 40.9 L 47.1 36.4 C 45.7 35.6 43.8 36.1 43 37.5 C 42.2 38.9 42.7 40.8 44.1 41.6 L 51.9 46.1 Z M 12.9 23.6 C 14.3 24.4 16.2 23.9 17 22.5 C 17.8 21.1 17.3 19.2 15.9 18.4 L 8.1 13.9 C 6.7 13.1 4.8 13.6 4 15 C 3.2 16.4 3.7 18.3 5.1 19.1 L 12.9 23.6 Z" />
<group
android:name="group"
android:pivotX="30"
android:pivotY="30">
<path
android:name="path_2"
android:fillAlpha="0.2"
android:fillColor="#000000"
android:pathData="M 56 15 C 55.5 14 54.4 13.5 53.4 13.5 C 52.9 13.5 52.4 13.6 51.9 13.9 L 44.1 18.4 C 42.7 19.2 42.2 21.1 43 22.5 C 43.6 23.5 44.6 24 45.6 24 C 46.1 24 46.6 23.9 47.1 23.6 L 54.9 19.1 C 56.3 18.3 56.8 16.4 56 15 Z" />
<path
android:name="path_3"
android:fillAlpha="0.4"
android:fillColor="#000000"
android:pathData="M 59.1 27.9 C 58.6 27.3 57.9 27 57 27 L 48 27 C 46.3 27 45 28.3 45 30 C 45 30.8 45.3 31.6 45.9 32.1 C 46.4 32.6 47.2 33 48 33 L 57 33 C 58.7 33 60 31.7 60 30 C 60 29.2 59.7 28.4 59.1 27.9 Z" />
<path
android:name="path_4"
android:fillAlpha="0.6"
android:fillColor="#000000"
android:pathData="M 54.9 40.9 L 47.1 36.4 C 45.7 35.6 43.8 36.1 43 37.5 C 42.7 38 42.6 38.5 42.6 39 C 42.6 40 43.1 41 44.1 41.6 L 51.9 46.1 C 53.3 46.9 55.2 46.4 56 45 C 56.3 44.5 56.4 44 56.4 43.5 C 56.4 42.5 55.9 41.5 54.9 40.9 Z" />
<path
android:name="path_5"
android:fillAlpha="0.8"
android:fillColor="#000000"
android:pathData="M 46.1 51.9 L 41.6 44.1 C 40.8 42.7 38.9 42.2 37.5 43 C 36.5 43.6 36 44.6 36 45.6 C 36 46.1 36.1 46.6 36.4 47.1 L 40.9 54.9 C 41.7 56.3 43.6 56.8 45 56 C 46 55.4 46.5 54.4 46.5 53.4 C 46.5 52.9 46.4 52.4 46.1 51.9 Z" />
<path
android:name="path_6"
android:fillColor="#000000"
android:pathData="M 30 45 C 29.2 45 28.4 45.3 27.9 45.9 C 27.4 46.4 27 47.2 27 48 L 27 57 C 27 58.7 28.3 60 30 60 C 30.8 60 31.6 59.7 32.1 59.1 C 32.6 58.6 33 57.8 33 57 L 33 48 C 33 46.3 31.7 45 30 45 Z" />
</group>
</vector>
</aapt:attr>
<target android:name="group">
<aapt:attr name="android:animation">
<set android:ordering="sequentially">
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="0"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="30"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="30"
android:valueTo="30"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="30"
android:valueTo="60"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="60"
android:valueTo="60"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="60"
android:valueTo="90"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="90"
android:valueTo="90"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="90"
android:valueTo="120"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="120"
android:valueTo="120"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="120"
android:valueTo="150"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="150"
android:valueTo="150"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="150"
android:valueTo="180"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="180"
android:valueTo="180"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="180"
android:valueTo="210"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="210"
android:valueTo="210"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="210"
android:valueTo="240"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="240"
android:valueTo="240"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="240"
android:valueTo="270"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="270"
android:valueTo="270"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="270"
android:valueTo="300"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="300"
android:valueTo="300"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="300"
android:valueTo="330"
android:valueType="floatType" />
<objectAnimator
android:duration="100"
android:propertyName="rotation"
android:valueFrom="330"
android:valueTo="330"
android:valueType="floatType" />
<objectAnimator
android:duration="1"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:propertyName="rotation"
android:valueFrom="330"
android:valueTo="360"
android:valueType="floatType" />
</set>
</aapt:attr>
</target>
</animated-vector>
{
"version": 1,
"layers": {
"vectorLayer": {
"id": "560",
"name": "vector",
"type": "vector",
"width": 60,
"height": 60,
"children": [
{
"id": "428",
"name": "path_1",
"type": "path",
"pathData": "M 33 12 C 33 13.7 31.7 15 30 15 C 28.3 15 27 13.7 27 12 L 27 3 C 27 1.3 28.3 0 30 0 C 31.7 0 33 1.3 33 3 L 33 12 Z M 33 48 C 33 46.3 31.7 45 30 45 C 28.3 45 27 46.3 27 48 L 27 57 C 27 58.7 28.3 60 30 60 C 31.7 60 33 58.7 33 57 L 33 48 Z M 3 27 C 1.3 27 0 28.3 0 30 C 0 31.7 1.3 33 3 33 L 12 33 C 13.7 33 15 31.7 15 30 C 15 28.3 13.7 27 12 27 L 3 27 Z M 48 27 C 46.3 27 45 28.3 45 30 C 45 31.7 46.3 33 48 33 L 57 33 C 58.7 33 60 31.7 60 30 C 60 28.3 58.7 27 57 27 L 48 27 Z M 5.1 40.9 C 3.7 41.8 3.2 43.6 4 45 C 4.8 46.4 6.7 46.9 8.1 46.1 L 15.9 41.6 C 17.3 40.8 17.8 38.9 17 37.5 C 16.2 36.1 14.3 35.6 12.9 36.4 L 5.1 40.9 Z M 44.1 18.4 C 42.7 19.2 42.2 21.1 43 22.5 C 43.8 23.9 45.7 24.4 47.1 23.6 L 54.9 19.1 C 56.3 18.3 56.8 16.4 56 15 C 55.2 13.6 53.3 13.1 51.9 13.9 L 44.1 18.4 Z M 40.9 54.9 C 41.7 56.3 43.6 56.8 45 56 C 46.4 55.2 46.9 53.3 46.1 51.9 L 41.6 44.1 C 40.8 42.7 38.9 42.2 37.5 43 C 36.1 43.8 35.6 45.7 36.4 47.1 L 40.9 54.9 Z M 18.4 15.9 C 19.2 17.3 21.1 17.8 22.5 17 C 23.9 16.2 24.4 14.3 23.6 12.9 L 19.1 5.1 C 18.3 3.7 16.4 3.2 15 4 C 13.6 4.8 13.1 6.7 13.9 8.1 L 18.4 15.9 Z M 13.9 51.9 C 13.1 53.3 13.6 55.2 15 56 C 16.4 56.8 18.3 56.3 19.1 54.9 L 23.6 47.1 C 24.4 45.7 23.9 43.8 22.5 43 C 21.1 42.2 19.2 42.7 18.4 44.1 L 13.9 51.9 Z M 36.4 12.9 C 35.6 14.3 36.1 16.2 37.5 17 C 38.9 17.8 40.8 17.3 41.6 15.9 L 46.1 8.1 C 46.9 6.7 46.4 4.8 45 4 C 43.6 3.2 41.7 3.7 40.9 5.1 L 36.4 12.9 Z M 51.9 46.1 C 53.3 46.9 55.2 46.4 56 45 C 56.8 43.6 56.3 41.7 54.9 40.9 L 47.1 36.4 C 45.7 35.6 43.8 36.1 43 37.5 C 42.2 38.9 42.7 40.8 44.1 41.6 L 51.9 46.1 Z M 12.9 23.6 C 14.3 24.4 16.2 23.9 17 22.5 C 17.8 21.1 17.3 19.2 15.9 18.4 L 8.1 13.9 C 6.7 13.1 4.8 13.6 4 15 C 3.2 16.4 3.7 18.3 5.1 19.1 L 12.9 23.6 Z",
"fillColor": "#231f20",
"fillAlpha": 0.2,
"strokeWidth": 1
},
{
"id": "563",
"name": "group",
"type": "group",
"pivotX": 30,
"pivotY": 30,
"children": [
{
"id": "454",
"name": "path_2",
"type": "path",
"pathData": "M 56 15 C 55.5 14 54.4 13.5 53.4 13.5 C 52.9 13.5 52.4 13.6 51.9 13.9 L 44.1 18.4 C 42.7 19.2 42.2 21.1 43 22.5 C 43.6 23.5 44.6 24 45.6 24 C 46.1 24 46.6 23.9 47.1 23.6 L 54.9 19.1 C 56.3 18.3 56.8 16.4 56 15 Z",
"fillColor": "#231f20",
"fillAlpha": 0.2,
"strokeWidth": 1
},
{
"id": "480",
"name": "path_3",
"type": "path",
"pathData": "M 59.1 27.9 C 58.6 27.3 57.9 27 57 27 L 48 27 C 46.3 27 45 28.3 45 30 C 45 30.8 45.3 31.6 45.9 32.1 C 46.4 32.6 47.2 33 48 33 L 57 33 C 58.7 33 60 31.7 60 30 C 60 29.2 59.7 28.4 59.1 27.9 Z",
"fillColor": "#231f20",
"fillAlpha": 0.4,
"strokeWidth": 1
},
{
"id": "506",
"name": "path_4",
"type": "path",
"pathData": "M 54.9 40.9 L 47.1 36.4 C 45.7 35.6 43.8 36.1 43 37.5 C 42.7 38 42.6 38.5 42.6 39 C 42.6 40 43.1 41 44.1 41.6 L 51.9 46.1 C 53.3 46.9 55.2 46.4 56 45 C 56.3 44.5 56.4 44 56.4 43.5 C 56.4 42.5 55.9 41.5 54.9 40.9 Z",
"fillColor": "#231f20",
"fillAlpha": 0.6,
"strokeWidth": 1
},
{
"id": "532",
"name": "path_5",
"type": "path",
"pathData": "M 46.1 51.9 L 41.6 44.1 C 40.8 42.7 38.9 42.2 37.5 43 C 36.5 43.6 36 44.6 36 45.6 C 36 46.1 36.1 46.6 36.4 47.1 L 40.9 54.9 C 41.7 56.3 43.6 56.8 45 56 C 46 55.4 46.5 54.4 46.5 53.4 C 46.5 52.9 46.4 52.4 46.1 51.9 Z",
"fillColor": "#231f20",
"fillAlpha": 0.8,
"strokeWidth": 1
},
{
"id": "558",
"name": "path_6",
"type": "path",
"pathData": "M 30 45 C 29.2 45 28.4 45.3 27.9 45.9 C 27.4 46.4 27 47.2 27 48 L 27 57 C 27 58.7 28.3 60 30 60 C 30.8 60 31.6 59.7 32.1 59.1 C 32.6 58.6 33 57.8 33 57 L 33 48 C 33 46.3 31.7 45 30 45 Z",
"fillColor": "#231f20",
"strokeWidth": 1
}
]
}
]
},
"hiddenLayerIds": []
},
"timeline": {
"animation": {
"id": "562",
"name": "anim",
"duration": 1201,
"blocks": [
{
"id": "565",
"layerId": "563",
"propertyName": "rotation",
"startTime": 100,
"endTime": 101,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 0,
"toValue": 30
},
{
"id": "567",
"layerId": "563",
"propertyName": "rotation",
"startTime": 200,
"endTime": 201,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 30,
"toValue": 60
},
{
"id": "568",
"layerId": "563",
"propertyName": "rotation",
"startTime": 300,
"endTime": 301,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 60,
"toValue": 90
},
{
"id": "569",
"layerId": "563",
"propertyName": "rotation",
"startTime": 400,
"endTime": 401,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 90,
"toValue": 120
},
{
"id": "570",
"layerId": "563",
"propertyName": "rotation",
"startTime": 500,
"endTime": 501,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 120,
"toValue": 150
},
{
"id": "571",
"layerId": "563",
"propertyName": "rotation",
"startTime": 600,
"endTime": 601,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 150,
"toValue": 180
},
{
"id": "572",
"layerId": "563",
"propertyName": "rotation",
"startTime": 700,
"endTime": 701,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 180,
"toValue": 210
},
{
"id": "573",
"layerId": "563",
"propertyName": "rotation",
"startTime": 800,
"endTime": 801,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 210,
"toValue": 240
},
{
"id": "575",
"layerId": "563",
"propertyName": "rotation",
"startTime": 900,
"endTime": 901,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 240,
"toValue": 270
},
{
"id": "576",
"layerId": "563",
"propertyName": "rotation",
"startTime": 1000,
"endTime": 1001,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 270,
"toValue": 300
},
{
"id": "577",
"layerId": "563",
"propertyName": "rotation",
"startTime": 1100,
"endTime": 1101,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 300,
"toValue": 330
},
{
"id": "578",
"layerId": "563",
"propertyName": "rotation",
"startTime": 1200,
"endTime": 1201,
"interpolator": "FAST_OUT_SLOW_IN",
"type": "number",
"fromValue": 330,
"toValue": 360
}
]
}
}
}
@ugommirikwe
Copy link

To change the color programmatically, you'd use the <asAnimatedVectorDrawable>.setTint(color), quite like so:

(ContextCompat.getDrawable(context, R.drawable.ic_spinner_animated) as AnimatedVectorDrawable)
  .apply {
     setTint(trueColor)
     start()
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment