「解决方案」Android Vector动画实现三个小球循环转动的加载动画

  公司项目中需要使用到一个三个小球循环转动的加载动画,最初给的是一帧帧的切图做帧动画,后来在android sdk25上面发生了内存泄漏Out Of Memory(OOM),于是就考虑着更换一下实现方式,于是就开始尝试使用Vector矢量动画来实现了。

效果预览

Vector矢量加载动画

原始Vector

  在drawable目录下创建一个名为icon_pull_refresh的xml文件。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="600dp"
android:height="200dp"
android:viewportWidth="600"
android:viewportHeight="200">

<group android:name="left">
<path
android:fillColor="#FF00FF"
android:pathData="M75 148 a 48 48 0 1 0 -1 0z" />
</group>

<group android:name="middle">
<path
android:fillColor="#FF00FF"
android:pathData="M300 175 a 75 75 0 1 0 -1 0z" />
</group>

<group android:name="right">
<path
android:fillColor="#FF00FF"
android:pathData="M525 148 a 48 48 0 1 0 -1 0z" />
</group>

</vector>

属性动画

左侧小球转动到中间

  在animator目录下创建名为animator_pull_refresh_left2middle的xml文件。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

<objectAnimator
android:duration="1000"
android:propertyName="translateX"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="0"
android:valueTo="182.8125"
android:valueType="floatType"/>

<objectAnimator
android:duration="1000"
android:propertyName="translateY"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="0"
android:valueTo="-56.25"
android:valueType="floatType"/>

<objectAnimator
android:duration="1000"
android:propertyName="scaleX"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="1"
android:valueTo="1.5625"
android:valueType="floatType"/>

<objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="1"
android:valueTo="1.5625"
android:valueType="floatType"/>

</set>

中间小球转动到右边

  在animator目录下创建名为animator_pull_refresh_middle2right的xml文件。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

<objectAnimator
android:duration="1000"
android:propertyName="translateX"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="0"
android:valueTo="333"
android:valueType="floatType"/>

<objectAnimator
android:duration="1000"
android:propertyName="translateY"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="0"
android:valueTo="36"
android:valueType="floatType"/>

<objectAnimator
android:duration="1000"
android:propertyName="scaleX"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="1"
android:valueTo="0.64"
android:valueType="floatType"/>

<objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="1"
android:valueTo="0.64"
android:valueType="floatType"/>
</set>

右侧小球转动到左边

  在animator目录下创建名为animator_pull_refresh_right2left的xml文件。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<set>

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="translateX"
android:repeatCount="infinite"
android:repeatMode="restart"
android:valueFrom="0"
android:valueTo="-450"
android:valueType="floatType"/>

</set>

Vector矢量动画实现

  在drawble目录下创建名为animation_refresh的xml文件。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_pull_refresh">
<target
android:name="left"
android:animation="@animator/animator_pull_refresh_left2middle" />
<target
android:name="middle"
android:animation="@animator/animator_pull_refresh_middle2right" />
<target
android:name="right"
android:animation="@animator/animator_pull_refresh_right2left" />
</animated-vector>

使用矢量动画

  在布局文件中使用矢量动画

1
2
3
4
5
<androidx.appcompat.widget.AppCompatImageView
app:srcCompat="@drawable/animation_refresh"
android:layout_width="wrap_content"
android:id="@+id/aciv_refresh"
android:layout_height="wrap_content" />

  在代码中执行矢量动画

1
(acivRefresh.drawable as AnimatedVectorDrawable).start()

写在最后

  最终Android Vector矢量动画方案实现了三个小球循环转动的加载动画。但是由于实现方案复杂,改动困难最终方案又被pass了。考虑到现在sdk25存量已经比较小了,因此不考虑使用此替代方案。最终把关注点放到了内存泄漏上。