Android 属性动画 浅析

什么是属性动画

属性动画,通过修改View 本身的属性,达到动画的效果。例如修改view 的 位置 让他实现移动的效果,修改view 的alpha 实现 透明度的效果

属性动画和补间动画有什么区别

虽然都是动画,但是二者最大的区别在于,补间动画只是修改了视图部分,并没有改变view 本身的属性,而 属性动画修改了他的属性,

比如 View1 使用属性动画向右移动 200 像素,动画结束以后,他就在 200 像素的位置 并且点击移动以后的 View1 是有点击效果的
View2 使用补间动画 向右移动200像素,动画结束以后,他会回到原来的位置,并且,如果你在移动过程中,点击 view2 是没有任何效果的,

其本质就在于,补间动画,他只是看着像是移动了,实际上从未离开, 属性动画 就是真的走了

使用ViewPropertyAnimator

就属性动画而言,ViewPropertyAnimator 是Android 开发中使用频率较高的动画了。下面是一个简单的示例,向右移动400像素

1
2
3
4
view_anim.animate()
.translationX(400f)
.setDuration(1000)
.start()

一行代码就实现了 属性动画,使用非常方便,看一下 animate() 方法,返回的就是一个 ViewPropertyAnimator

1
2
3
4
5
6
public ViewPropertyAnimator animate() {
if (mAnimator == null) {
mAnimator = new ViewPropertyAnimator(this);
}
return mAnimator;
}

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

来源HenCoder

By 方法是啥??

细心的朋友发现,所有 ViewPropertyAnimator 相关的方法都有一个 By 方法 ,这个 By 方法代表什么含义呢?

写一个简单的示例进行测试

1
2
3
4
5
6
7
8
9
10
11

btn_translate.setOnClickListener {
view_anim.animate()
.translationX(200f)
.setDuration(1000)
.start()
view_anim_2.animate()
.translationXBy(200f)
.setDuration(1000)
.start()
}

对比之下能够发现,

translationX 移动到指定位置以后,再次点击就不能够在移动了。
translationXBy 移动到指定位置以后,再次点击就还是能够继续移动的,
By 方法是移动完成以后,会在变化以后的属性上继续变化属性

使用 ValueAnimator 实现属性动画效果

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

为什么要先说,ValueAnimator,虽然他不常用,但是 下面要说的 ObjectAnimator 就是继承于 ValueAnimator

ValueAnimator 有两种方式可以实现属性动画

使用代码的方式

1
2
3
4
5
6
7
8
9
10
ValueAnimator.ofFloat(0f, 400f)
.apply {
duration = 1000
//监听器
addUpdateListener {
//在这里将view 的属性进行修改
view_anim_3.translationX = it.animatedValue as Float
}
}
.start()

使用xml 的方式

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

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

</animator>
1
2
3
4
5
6
7
8
9
// ValueAnimator xml 方式
val anim = AnimatorInflater.loadAnimator(this, R.animator.translate) as ValueAnimator
//绑定到view
anim.setTarget(view_anim_4)
//添加监听器
anim.addUpdateListener {
view_anim_4.translationX = it.animatedValue as Float
}
anim.start()

效果和代码实现的完全一样

ValueAnimator 几个重要的方法

ofFloat

1
2
ValueAnimator.ofInt(0f, 400f)
android:valueType="floatType"

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

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

ofInt

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

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

ofObject

1
ValueAnimator ofObject(TypeEvaluator evaluator, Object... values)

TypeEvaluator 就是估值器,他的作用 处理数值变化的时候变化的逻辑

查看源码可以知道 ,这是一个接口

1
2
3
4
5
public interface TypeEvaluator<T> {

public T evaluate(float fraction, T startValue, T endValue);

}

点开它的实现类,能够找到 FloatEvaluator 估值器 和 IntEvaluator 估值器

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));
}
}

仿造上面的示例 就能够写出自己的估值器

1
2
3
4
//自定义的类
data class CustomData(
var value: Float
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//自定义的估值器
class CustomEvaluator : TypeEvaluator<CustomData> {
override fun evaluate(
fraction: Float,
startValue: CustomData,
endValue: CustomData
): CustomData {
var value = startValue.value
value += fraction * (endValue.value - value)
return CustomData(value)

}

}

使用 ofObject

1
2
3
4
5
6
7
8
9
10
 btn_translate.setOnClickListener {
ValueAnimator.ofObject(CustomEvaluator(),CustomData(0f),CustomData(400f))
.apply {
duration = 1000
addUpdateListener {
view_anim.translationX = (it.animatedValue as CustomData).value
}
}
.start()
}

使用 ObjectAnimator 实现属性动画效果

在上面说到 ObjectAnimator 是继承与 ValueAnimator,二者很相似,都是通过通过监听数值变化在给对象赋值,他们的区别就在于

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

他的使用和 ValueAnimator 机会相同

使用代码的方式

1
2
3
4
5
ObjectAnimator.ofFloat(view_anim_2, "translationX", 0f, 400f)
.apply {
duration = 1000
}
.start()

使用xml 的方式

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

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

</objectAnimator>
1
2
3
4
val animObj = AnimatorInflater.loadAnimator(this, R.animator.translate_obj) as ObjectAnimator
//绑定到view
animObj.target = view_anim_5
animObj.start()

插值器 Interpolator

插值器和估值器 有着本质的区别

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

Android 也提供了 很多 插值器供开发者选择

作用资源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 动画:你真的会使用插值器与估值器吗?(含详细实例教学)

系统默认的插值器是AccelerateDecelerateInterpolator,即先加速后减速

动画的监听器

先看一下 Animator 的继承关系

Animator 的监听器

先看一下 作为 抽象类 的 Animator 自身的监听器

  • addPauseListener(AnimatorPauseListener listener)
    • onAnimationPause
    • onAnimationResume
  • addListener(AnimatorListener listener)
    • onAnimationStart
    • onAnimationEnd
    • onAnimationCancel
    • onAnimationRepeat

ValueAnimator的监听器

  • addUpdateListener(AnimatorUpdateListener listener)
    • onAnimationUpdate

ObjectAnimator

ObjectAnimator 继承自 ValueAnimator ,所以他拥有 上面的3个接口

在kotlin 中,使用了拓展函数的方法,将 addPauseListeneraddListener 做了处理

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
val valueAnimator = ValueAnimator.ofFloat(0f, 800f)
valueAnimator
.apply {
duration = 2000
repeatCount = ValueAnimator.INFINITE
repeatMode = ValueAnimator.REVERSE
addUpdateListener {
view_anim_2.translationX = it.animatedValue as Float
}

doOnEnd { view_anim_2.text = "属性动画结束" }
doOnStart { view_anim_2.text = "属性动画开始" }
doOnCancel { view_anim_2.text = "属性动画曲线" }
doOnRepeat { view_anim_2.text = "属性动画重复" }

doOnPause { view_anim_2.text = "属性动画暂停" }
doOnResume { view_anim_2.text = "属性动画回复" }

}
.start()

view_anim_2.setOnClickListener {
if(!valueAnimator.isPaused){
valueAnimator.pause()
}else{
valueAnimator.resume()
}

}