属性动画
随时间更改任何对象属性的动画,无论其是否绘制到屏幕上。属性动画会在指定时长内更改属性的值。
ValueAnimator
Animator子类,主要作用在给定时间给定插值器(默认为线下插值器LinearInterpolator)下计算值变化。主要获取方法ofInt()、ofFloat() 或 ofObject()。
//线性变化0到100
ValueAnimator.ofFloat(0f, 100f).apply {
duration = 200
addUpdateListener {
textView.translationX = it.animatedValue as Float
}
start()
}
xml创建,为了和视图动画区分属性动画的XML文件保存到 res/animator/
res\animator\value_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:repeatCount="1"
android:repeatMode="restart"
android:valueFrom="0"
android:valueTo="100"
android:valueType="floatType" />
加载
(AnimatorInflater.loadAnimator(this, R.animator.value_animator) as ValueAnimator).apply {
addUpdateListener {
textView.translationX = it.animatedValue as Float
}
start()
}
ObjectAnimator
ValueAnimator的子类,添加了对目标对象命名属性动画的效果。主要获取方法ofInt()、ofFloat() 或 ofObject()。相比ValueAnimator多了目标对象和目标对象的属性。
//更新translationX属性
ObjectAnimator.ofFloat(textView, "translationX", 0f,100f).apply {
duration=200
start()
}
xml 创建
res\animator\object_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:valueTo="100"
android:valueFrom="0"
android:valueType="floatType"
android:propertyName="translationX"
android:repeatCount="1"
android:repeatMode="restart"/>
加载
(AnimatorInflater.loadAnimator(this, R.animator.object_animator) as ObjectAnimator).apply {
target = textView
start()
}
注意:对象属性必须具有 set<PropertyName>()形式的 setter 函数(采用驼峰式大小写形式)
AnimatorSet
主要作用为将多个Animator动画按顺序.一起播放或延迟播放。
直接添加
playSequentially按顺序播放一组Animator动画
playTogether同时播放一组Animator动画
val annotation1 = ObjectAnimator.ofFloat(binding.textView, "translationX", 0f, 100f)
val annotation2 = ObjectAnimator.ofFloat(binding.textView, "translationY", 0f, 100f)
AnimatorSet().apply {
//按顺序播放
playSequentially(annotation1,annotation2)
//同时播放
//playTogether(annotation1,annotation2)
start()
}
使用AnimatorSet.Builder,用于构建动画的依赖关系,注意,只有先调用AnimatorSet#play(Animator),然后才能依赖关系主要方法
afterplay(Animator)添加动画依赖在此动画之后执行
beforeplay(Animator)添加动画依赖在此动画之前执行
with和play(Animator)添加动画一起执行
val annotation1 = ObjectAnimator.ofFloat(binding.textView, "translationX", 0f, 100f)
val annotation2 = ObjectAnimator.ofFloat(binding.textView, "translationY", 0f, 100f)
val builder = AnimatorSet().apply {
//annotation1在annotation2后面执行
play(annotation1).after(annotation2)
}
AnimatorSet().apply {
play(builder)
start()
}
TypeEvaluator(类型评估)
当需要为Android系统无法识别的类型添加动画效果,可以通过实现TypeEvaluator接口来创建您自己的评估程序。TypeEvaluator 接口中只有一种要实现的方法,可以查看系统中实现的类FloatEvaluator
class FloatEvaluator : TypeEvaluator<Number> {
override fun evaluate(
fraction: Float, //从起始值到结束值的百分数
startValue: Number,//开始值
endValue: Number//结束值
): Float {
val startFloat: Float = startValue.toFloat()
return startFloat + fraction * (endValue.toFloat() - startFloat)
}
}
TimeInterpolator(插值器)
插值器指定了如何根据时间计算动画中的特定值。例如,您可以指定动画在整个动画中以线性方式播放,即动画在整个播放期间匀速移动;也可以指定动画使用非线性时间,例如动画在开始后加速并在结束前减速。

getInterpolation方法
class MyInterpolator : TimeInterpolator{
override fun getInterpolation(input: Float): Float {
//input为动画播放的百分比 插值器通过修改此值来调整动画速率
return input
}
}
Keyframe(关键帧)
Keyframe由时间和当前状态组成,动画在随时间由前一个关键帧进入下一个关键帧。每个关键帧还包含一个可选TimeInterpolator 对象,该对象定义了关键帧之前的时间间隔内的时间插值。代码实现
val kf0 = Keyframe.ofFloat(0f, 0f)
val kf1 = Keyframe.ofFloat(.5f, 360f)
//关键帧kf1到kf2的插值器
kf1.interpolator= OvershootInterpolator()
val kf2 = Keyframe.ofFloat(1f, 0f)
val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2)
ObjectAnimator.ofPropertyValuesHolder(binding.textView, pvhRotation).apply {
duration = 5000
start()
}
从API 23开始可使用xml实现res\animator\key_frame.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000">
<propertyValuesHolder android:propertyName="rotation">
<keyframe
android:fraction="0"
android:value="0"
android:valueType="floatType"></keyframe>
<keyframe
android:fraction="0.5"
android:value="360"
android:interpolator="@android:anim/overshoot_interpolator"
android:valueType="floatType"></keyframe>
<keyframe
android:fraction="1"
android:value="0"
android:valueType="floatType"></keyframe>
</propertyValuesHolder>
</objectAnimator>
加载
(AnimatorInflater.loadAnimator(this, R.animator.key_frame) as ObjectAnimator).apply {
target = binding.textView
start()
}
xml和代码实现效果相同

ViewGroup布局更改动画
ViewGroup布局更改动画主要通过 LayoutTransition 类来实现。当向ViewGroup中添加或者移除视图时,或使用 VISIBLE、INVISIBLE 或 GONE 调用视图的 setVisibility() 方法时。都可定义ViewGroup中view的变化动画。主要定义LayoutTransition类并调用LayoutTransition的setAnimator()方法传入LayoutTransition 常量和 Animator对象。然后将LayoutTransition设置到ViewGroup中。LayoutTransition 常量主要为:
APPEARING:ViewGroup中view的显示动画CHANGE_APPEARING:ViewGroup中view显示时,相连view移动动画DISAPPEARING:ViewGroup中隐藏view时,view的消失动画CHANGE_DISAPPEARING:ViewGroup中隐藏view时,相连view移动动画
//定义动画
val animator = ObjectAnimator.ofFloat(Any(), "rotation", 0f, 360f)
val layoutTransition= LayoutTransition()
//ViewGroup中子view显示时的动画
layoutTransition.setAnimator(LayoutTransition.APPEARING,animator)
binding.rootLayout.layoutTransition= layoutTransition
使用默认的ViewGroup布局更改动画可在布局文件中添加android:animateLayoutChanges="true"
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true" />
StateListAnimator
视图状态更改动画,可以给view在不同状态下设置动画(如按下、聚焦)。示例res\xml\state_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<set>
<!-- 按下时放打大1.5倍 -->
<objectAnimator android:propertyName="scaleX"
android:duration="100"
android:valueTo="1.5"
android:valueType="floatType"/>
<objectAnimator android:propertyName="scaleY"
android:duration="100"
android:valueTo="1.5"
android:valueType="floatType"/>
</set>
</item>
<item android:state_pressed="false">
<set>
<!-- 取消按压时还原 -->
<objectAnimator android:propertyName="scaleX"
android:duration="100"
android:valueTo="1"
android:valueType="floatType"/>
<objectAnimator android:propertyName="scaleY"
android:duration="100"
android:valueTo="1"
android:valueType="floatType"/>
</set>
</item>
</selector>
直接布局中使用
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:stateListAnimator="@xml/state_animator"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
代码加载
val stateListAnimator = AnimatorInflater.loadStateListAnimator(this, R.xml.state_animator)
binding.button.stateListAnimator = stateListAnimator
效果

ViewPropertyAnimator
ViewPropertyAnimator使用单个Animator对象为view多个属性并行添加动画。 ObjectAnimator 非常相似但相比更加高效简洁。使用多个 ObjectAnimator 对象、使用单个 ObjectAnimator 对象以及使用 ViewPropertyAnimator 的区别。
多个 ObjectAnimator 对象
val animX = ObjectAnimator.ofFloat(myView, "x", 50f)
val animY = ObjectAnimator.ofFloat(myView, "y", 100f)
AnimatorSet().apply {
playTogether(animX, animY)
start()
}
一个 ObjectAnimator
val pvhX = PropertyValuesHolder.ofFloat("x", 50f)
val pvhY = PropertyValuesHolder.ofFloat("y", 100f)
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start()
ViewPropertyAnimator
myView.animate().x(50f).y(100f)
AnimationDrawable(帧动画)
将多个连续图片组成的动画,示例 res\drawable\rocket_thrust.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<!--帧动画图片和持续时间-->
<item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
<item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
<item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>
代码中使用
val rocketImage = findViewById<ImageView>(R.id.rocket_image).apply {
//将帧动画设置到ImageView中
setBackgroundResource(R.drawable.rocket_thrust)
//获取AnimationDrawable对象
rocketAnimation = background as AnimationDrawable
}
//开始动画
rocketImage.setOnClickListener({ rocketAnimation.start() })
AnimatedVectorDrawable(矢量动画)
为矢量图添加动画,如旋转,路径变换等。首先我们需要给需要动画的group和path添加android:name 属性,以便在Animator引用。VectorDrawable中group和path定义的属性:

定义res/drawable/vectordrawable.xml:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="64dp"
android:width="64dp"
android:viewportHeight="600"
android:viewportWidth="600">
<!--定义 android:name属性 在后面Animator 中引用-->
<group
android:name="rotationGroup"
android:pivotX="300.0"
android:pivotY="300.0"
android:rotation="45.0" >
<path
android:name="v"
android:fillColor="#000000"
android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
</group>
</vector>
创建矢量动画AnimatedVectorDrawable的XML res/drawable/animatorvectordrawable.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vectordrawable" >
<!--将rotationGroup组设置rotation动画-->
<target
android:name="rotationGroup"
android:animation="@animator/rotation" />
<!--将路径设置path_morph动画-->
<target
android:name="v"
android:animation="@animator/path_morph" />
</animated-vector>
使用ObjectAnimator或AnimatorSet定义的动画XML
使用ObjectAnimator将目标组旋转 360 度res/animator/rotation.xml
<objectAnimator
android:duration="6000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360" />
使用AnimatorSet将矢量可绘制对象的路径从一个形状变为另一个形状 res/animator/path_morph.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="3000"
android:propertyName="pathData"
android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z"
android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z"
android:valueType="pathType" />
</set>
使用
//设置背景
binding.imageView.setImageResource(R.drawable.animatorvectordrawable)
//获取矢量动画
val animatedVectorDrawable= binding.imageView.drawable as AnimatedVectorDrawable
binding.imageView.setOnClickListener {
//开始动画
animatedVectorDrawable.start()
}
效果

DynamicAnimation(动力动画)
物理的动画的基础类,引用
implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
FlingAnimation(惯性动画)
一种持续初始动量(通常是手势速度)并且逐渐变慢的动画
val flingAnim = FlingAnimation(
view,
//View的translationX属性。
DynamicAnimation.TRANSLATION_X
)
//将开始速度设置为-2000(像素/秒)
.setStartVelocity(-2000f)
//可选,但建议为动画设置合理的最小和最大范围。
//在这种情况下,我们将指向和重新分别设置为-200和2000。
.setMinValue(-200f).setMaxValue(2000f)
//开始动画
flingAnim.start()
SpringAnimation(弹性动画)
使用
//创建动画以动画化视图的X属性,设置
//将会将弹簧弹回0,并以5000(像素/ s)的开始速度开始动画
val anim = SpringAnimation(view, DynamicAnimation.X, 0)
.setStartVelocity(5000f)
anim.start()
lottie(比较好的三方动画库)
Lottie是一个适用于Android,iOS,Web和Windows的库,它可以使用Bodymovin解析以json 格式导出的Adobe After Effects动画,并在移动设备和Web 上原生呈现它们!官网地址:airbnb.io/lottie