Android 动画整理---- 属性动画

Android 动画详解——–属性动画

前言

对于动画,大多数Android 开发都玩得挺好的,这里也就不献丑了,本文重在记录,已经自己对动画的一些理解,鉴于篇幅问题,分为三个文章

Android 动画整理— 帧动画
Android 动画整理— 补间动画
Android 动画整理— 属性动画

🔥🔥🔥本文重在自己的查漏补缺,非常推荐 大佬的
Android:手把手带你全面了解 动画的原理&使用
Android 动画 Animator 家族使用指南

类图关系

动画家族 大的就分成这几个类,下面一一介绍

使用 ValueAnimator 设置属性动画

通过监听数值变化,手动将变化的数值赋值给对象的属性 实现动画的效果

实现方式有两种 代码控制 或者 xml 控制

代码的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//设置透明度
btn_alpha.setOnClickListener {
cancel()
Log.i(MainActivity.TAG, "属性动画 设置透明度")
val alpha = ValueAnimator.ofFloat(0f, 1f)
alpha.duration = 3000
alpha.repeatCount = 0
//监听动画更新器
alpha.addUpdateListener {
// 获得改变后的值
val currentValue = it.animatedValue as Float
Log.i(MainActivity.TAG,"设置透明度 $currentValue")
//手动赋值 自己设置 view 的透明度
image.alpha = currentValue
}
//开始
alpha.start()
}

通过打印 能够看到 animatedValue 的参数是在不断变化

1
2
3
4
5
6
7
8
9
10
11
12
2020-07-21 17:32:54.230 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.0
2020-07-21 17:32:54.237 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.0
...省略中间日志
2020-07-21 17:32:55.489 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.3721084
2020-07-21 17:32:55.506 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.38022482
2020-07-21 17:32:55.522 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.38888544
2020-07-21 17:32:55.540 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.39758113
2020-07-21 17:32:55.556 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.405795
...省略中间日志
2020-07-21 17:32:57.208 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.99980015
2020-07-21 17:32:57.225 20872-20872/com.allens.androidanim I/allens: 设置透明度 0.99996686
2020-07-21 17:32:57.242 20872-20872/com.allens.androidanim I/allens: 设置透明度 1.0

xml 方式

首先在 res/animator 下新建一个 xml 使用 animator 标签

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:valueFrom="0f"
android:valueTo="1f"
android:repeatCount="0"
android:valueType="floatType"/>

然后使用AnimatorInflater.loadAnimator 获取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

private val alphaAnimator by lazy {
AnimatorInflater.loadAnimator(this,
R.animator.property_value_alpha
) as ValueAnimator
}

//设置透明度
btn_alpha.setOnClickListener {
cancel()
Log.i(MainActivity.TAG,"属性动画 设置透明度")
//绑定到view
alphaAnimator.setTarget(image)
//添加动画监听器
alphaAnimator.addUpdateListener {
// 获得改变后的值
val currentValue = it.animatedValue as Float
Log.i(MainActivity.TAG,"设置透明度 $currentValue")
//手动赋值 自己设置 view 的透明度
image.alpha = currentValue
}
//开始
alphaAnimator.start()
}

效果同上使用代码的方式是相同的

ValueAnimator 几个重要的方法

ofFloat

在上面的代码设置中可以看到 我们使用 ValueAnimator.ofFloat(0f, 1f) 以及在 xml 中使用 android:valueType="floatType"

这个 将初始值 以浮点型数值的形式 过渡到结束值

ofInt

ValueAnimator.ofInt(0, 500)
android:valueType="intType"

作用同上 区别在于 将初始值 以整型数值的形式 过渡到结束值

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
private val translate = ValueAnimator.ofInt(0, 500)
//设置位移
btn_translate.setOnClickListener {
cancel()
translate.duration = 3000
translate.repeatCount = 0
translate.addUpdateListener{
val currentValue = it.animatedValue as Int
Log.i(MainActivity.TAG,"设置位移 $currentValue")
image.translationX = currentValue.toFloat()
}
translate.start()
}

通过日志可以看到

1
2
3
4
5
6
7
8
9
2020-07-21 17:43:03.243 22204-22204/com.allens.androidanim I/allens: 设置位移 0
2020-07-21 17:43:03.340 22204-22204/com.allens.androidanim I/allens: 设置位移 0
2020-07-21 17:43:03.356 22204-22204/com.allens.androidanim I/allens: 设置位移 1
2020-07-21 17:43:03.373 22204-22204/com.allens.androidanim I/allens: 设置位移 1
2020-07-21 17:43:03.388 22204-22204/com.allens.androidanim I/allens: 设置位移 2
...省略部分日志
2020-07-21 17:43:06.175 22204-22204/com.allens.androidanim I/allens: 设置位移 499
2020-07-21 17:43:06.242 22204-22204/com.allens.androidanim I/allens: 设置位移 499
2020-07-21 17:43:06.259 22204-22204/com.allens.androidanim I/allens: 设置位移 500

ofObject

ValueAnimator.ofObject(估值器, object, object)

将初始值 以自定义类型的形式的形式 过渡到结束值

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private val set =
ValueAnimator.ofObject(CustomEvaluator(), CustomData(0f, 0f), CustomData(1f, 500f))

//设置组合动画
btn_set.setOnClickListener {
cancel()
set.duration = 3000
set.repeatCount = 0
set.addUpdateListener {
val currentValue = it.animatedValue as CustomData
Log.i(MainActivity.TAG, "设置组合动画 $currentValue")
image.alpha = currentValue.alpha
image.translationX = currentValue.translate
}
set.start()
}
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

//自定义的类
data class CustomData(
var alpha: Float,
var translate: Float
)

//自定义的估值器
class CustomEvaluator : TypeEvaluator<CustomData> {
override fun evaluate(
fraction: Float,
startValue: CustomData?,
endValue: CustomData?
): CustomData {


if (startValue == null || endValue == null) {
return CustomData(1.0f, 300f)
}
var startFloatAlpha = startValue.alpha
startFloatAlpha += fraction * (endValue.alpha - startFloatAlpha)

var startFloatTranslate = startValue.translate
startFloatTranslate += fraction * (endValue.translate - startFloatTranslate)
return CustomData(startFloatAlpha, startFloatTranslate)
}
}

通过日志可以看到

1
2
3
4
5
6
7
8
9
10
11
2020-07-21 19:07:59.568 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=0.0, translate=0.0)
2020-07-21 19:07:59.574 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=0.0, translate=0.0)
2020-07-21 19:07:59.591 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=7.921457E-5, translate=0.039607286)
2020-07-21 19:07:59.607 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=3.168881E-4, translate=0.15844405)
2020-07-21 19:07:59.624 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=7.1290135E-4, translate=0.35645068)
2020-07-21 19:07:59.641 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=0.0012301803, translate=0.61509013)
2020-07-21 19:07:59.657 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=0.0019331872, translate=0.9665936)
...省略部分日志
2020-07-21 19:08:02.546 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=0.99978507, translate=499.89255)
2020-07-21 19:08:02.563 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=0.99996686, translate=499.98343)
2020-07-21 19:08:02.580 29178-29178/com.allens.androidanim I/allens: 设置组合动画 CustomData(alpha=1.0, translate=500.0)

估值器 TypeEvaluator

在上面的 介绍 ofObject 的时候 有一个 估值器的东东。这里也说一下

估值器 的主要作用就是处理数值变化的时候变化的逻辑

实现方式

实现方式 也很简单就是 实现 TypeEvaluator 接口即可

上面的 ofObject 我们自定义了一个 估值器,那 ofInt ofFloat 长什么样子呢

查看TypeEvaluator被那些类实现,可以发现,

1
2
3
4
5
6
7
8
public class FloatEvaluator implements TypeEvaluator<Number> {
public Float evaluate(float fraction, Number startValue, Number endValue) {
//获取开始数值
float startFloat = startValue.floatValue();
//开始数值 + 系数 *(结束数值 - 开始数值)
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}
1
2
3
4
5
6
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}

仿造系统的写法,就实现了上面自定义的 CustomEvaluator

ObjectAnimator

通过监听数值变化,自动将变化的数值赋值给对象的属性 实现动画的效果

ObjectAnimator:通过监听数值变化,自动将变化的数值赋值给对象的属性 实现动画的效果
ValueAnimator :通过监听数值变化,手动将变化的数值赋值给对象的属性 实现动画的效果

代码方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private val alpha by lazy {
ObjectAnimator.ofFloat(image,"alpha",0f, 1f)
}

//设置透明度
btn_alpha.setOnClickListener {
cancel()
Log.i(MainActivity.TAG, "属性动画 设置透明度")
alpha.duration = 3000
alpha.repeatCount = 0
//开始
alpha.start()

}

xml 方式

使用 objectAnimator标签

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:valueFrom="0f"
android:valueTo="1f"
android:repeatCount="0"
android:propertyName="alpha"
android:valueType="floatType"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private val alphaAnimator by lazy {
AnimatorInflater.loadAnimator(this,
R.animator.property_object_alpha
) as ObjectAnimator
}

//设置透明度
btn_alpha.setOnClickListener {
cancel()
Log.i(MainActivity.TAG,"属性动画 设置透明度")
//绑定到view
alphaAnimator.target = image
//开始
alphaAnimator.start()
}

ViewPropertyAnimator

这个应该是平常使用上最简单,用的也比较多的

1
image.animate().alpha(0f).setDuration(2000).start()

一行代码完成属性动画

具体可以跟的方法以及方法所对应的 View 中的实际操作的方法如下图所示:

来源HenCoder

TimeAnimator

提供一条时间流(每个16或17ms回调一次方法)

插值器 Interpolator

引用大佬的文章

插值器(Interpolator)决定 值 的变化模式(匀速、加速blabla)
估值器(TypeEvaluator)决定 值 的具体变化数值

在大佬的HenCoder中描写的非常清楚 自定义 View 1-6:属性动画 Property Animation(上手篇) 各种插值器 以及效果都有

效果图

此图来自Android 动画 Animator 家族使用指南

作用资源ID对应的Java类
动画加速进行@android:anim/accelerate_interpolatorAccelerateInterpolator
快速完成动画,超出再回到结束样式@android:anim/overshoot_interpolatorOvershootInterpolator
先加速再减速@android:anim/accelerate_decelerate_interpolatorAccelerateDecelerateInterpolator
先退后再加速前进@android:anim/anticipate_interpolatorAnticipateInterpolator
先退后再加速前进,超出终点后再回终点@android:anim/anticipate_overshoot_interpolatorAnticipateOvershootInterpolator
最后阶段弹球效果@android:anim/bounce_interpolatorBounceInterpolator
周期运动@android:anim/cycle_interpolatorCycleInterpolator
减速@android:anim/decelerate_interpolatorDecelerateInterpolator
匀速@android:anim/linear_interpolatorLinearInterpolator

表格来自 Android 动画:你真的会使用插值器与估值器吗?(含详细实例教学)

自定义插值器

不献丑了 推荐 Android 动画:你真的会使用插值器与估值器吗?(含详细实例教学)

源码

博客
源码Github

参考

Android属性动画详解(一),属性动画基本用法
自定义 View 1-6:属性动画 Property Animation(上手篇)
Android:手把手带你全面了解 动画的原理&使用
Android 属性动画:这是一篇很详细的 属性动画 总结&攻略
Android 动画:你真的会使用插值器与估值器吗?(含详细实例教学)
Android 动画 Animator 家族使用指南