[TOC]
属性动画基础全记录
属性动画和View动画不同,它对作用对象进行了扩展,属性动画可以对任何对象做动画,甚至还可以没有对象,同时它的效果也得到了加强,不再只是支持四种简单的变换
使用
属性动画.png
1. ObjectAnimator、ValueAnimator
ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等
ObjectAnimator是ValueAnimator的子类,它能够对任意对象的任意属性进行动画操作,ObjectAnimator内部的工作机制是通过寻找特定属性的get和set方法,然后通过方法不断地对值进行改变,从而实现动画效果,因此进行动画的对象一定要有对应的属性及设置方法
| Object的方法 | 说明 | 补充 |
|---|---|---|
| ObjectAnimator.ofXXX(Object target, String propertyName, XXX... values) | target:进行属性动画的对象<br />propetyName:对象要改变的属性<br />XXX:属性的类型<br />values:个数不限的参数,设置多个,表示在设置时间内变换这些值 | ObjectAnimator的ofXXX方法有很多,根据对象需要更改的属性的类型来决定使用<br />例如 View 的平移、缩放、旋转角度和透明度可以使用ofFloat;View的背景色可以使用ofInt |
1.1 使用属性动画来实现简单的View动画
private void changeObjectTranslationX() {
ObjectAnimator.ofFloat(objectView,"translationX",100)
.setDuration(2000)
.start();
}
private void changeObjectScaleX() {
ObjectAnimator.ofFloat(objectView,"scaleX",0,1,2,1)
.setDuration(2000)
.start();
}
private void changeObjectRotation() {
ObjectAnimator.ofFloat(objectView,"rotation",0,100,180,360)
.setDuration(2000)
.start();
}
private void changeObjectAlpha() {
ObjectAnimator.ofFloat(objectView,"alpha",0f,0.2f,0.5f,0.7f,1f)
.setDuration(2000)
.start();
}
private void changeObjectColor() {
ObjectAnimator.ofInt(objectView,"backgroundColor",0xFFFF0000,0xFFFB742E)
.setDuration(2000)
.start();
}
private void changeObjectSet() {
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(objectView, "translationX", 100),
ObjectAnimator.ofFloat(objectView, "scaleX", 0, 1, 2, 1),
ObjectAnimator.ofFloat(objectView, "rotation", 0, 100, 180, 360),
ObjectAnimator.ofFloat(objectView, "alpha", 0f, 0.2f, 0.5f, 0.7f, 1f),
ObjectAnimator.ofInt(objectView, "backgroundColor", 0xFFFF0000, 0xFFFB742E)
);
// set.setDuration(2000).start();
set = (AnimatorSet) AnimatorInflater.loadAnimator(this,R.animator.obejct_animation_set);
set.setTarget(objectView);
set.start();
}
XML写法
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:propertyName="translationX"
android:duration="2000"
android:valueFrom="0"
android:valueTo="100"/>
<objectAnimator
android:propertyName="scaleX"
android:valueFrom="0"
android:duration="2000"
android:valueTo="1"
/>
<objectAnimator
android:propertyName="scaleY"
android:valueFrom="0"
android:duration="2000"
android:valueTo="1"
/>
<objectAnimator
android:propertyName="rotation"
android:valueFrom="0"
android:duration="2000"
android:valueTo="360"
/>
<objectAnimator
android:propertyName="alpha"
android:valueFrom="0.5"
android:duration="2000"
android:valueTo="1"
/>
<objectAnimator
android:propertyName="backgroundColor"
android:duration="2000"
android:valueFrom="#fb742e"
android:valueTo="#FF0000"
/>
</set>
propertyName 对象要改变的属性 duration 持续时间 ordering 播放顺序 together:同时播放<br />sequentially:顺序播放 valueFrom 属性起始值 valueTo 属性结束值 startOffset 动画开始后的延迟时间 repeatCount 重复次数 repeatMode 重复模式 restart:重复播放<br /> reverse:倒放 valueType 属性类型
2. 插值器与估值器
2.1 时间插值器 TimeInterpolator
根据时间流逝的百分比来计算出当前属性值改变的百分比
| 系统预置插值器 | 名称 | 补充 |
|---|---|---|
| LinearInterpolator | 线性插值器 | 速度一直一致,加速度为0 |
| AccelerateDecelerateInterpolator | 加速减速插值器 | 先加速后减速,加速度先增后减 |
| DecelerateInterpolator | 减速插值器 | 一直减速,加速度一直减小 |
| ... |
2.2 估值器 TypeEvalutor
根据当前属性改变的百分比计算改变后的属性值
| 系统预置估值器 | 补充 |
|---|---|
| IntEvaluator | 针对整型 |
| FloatEvalutor | 针对浮点型 |
| ArgbEvaluator | 针对Color属性 |
| ... |
插值器提供当前动画的完成度或者属性应变换到的当前完成比,而插值器则是根据完成比计算出当前具体的值
由于动画的默认刷新率为10ms/帧,假设动画分5帧,对应线性插值器来说,第二帧动画就应该是完成比为40%的动画画面 ,对应插值器则是计算此时属性变化差值为变换总值乘以该百分比
3.属性动画监听
3.1 AnimatorListener
监听动画的开始、结束、取消、重复播放
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//开始时调用
Log.e(TAG, "onAnimationStart: ");
}
@Override
public void onAnimationEnd(Animator animation) {
//结束时调用
Log.e(TAG, "onAnimationEnd: " );
}
@Override
public void onAnimationCancel(Animator animation) {
//取消时调用
Log.e(TAG, "onAnimationCancel: " );
}
@Override
public void onAnimationRepeat(Animator animation) {
//重复时调用
Log.e(TAG, "onAnimationRepeat: ");
}
});
3.2 AnimatorPauseListener
监听动画的暂停与恢复
animator.addPauseListener(new Animator.AnimatorPauseListener() {
@Override
public void onAnimationPause(Animator animation) {
//暂停时调用
}
@Override
public void onAnimationResume(Animator animation) {
//恢复时调用
}
});
3.3 AnimatorListenerAdapter
对上面两个监听的监听方法进行了空实现,方便我们重写自己需要的监听方法
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
Log.e(TAG, "onAnimationStart: ");
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Log.e(TAG, "onAnimationEnd: " );
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
Log.e(TAG, "onAnimationCancel: " );
}
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
Log.e(TAG, "onAnimationRepeat: ");
}
@Override
public void onAnimationPause(Animator animation) {
super.onAnimationPause(animation);
Log.e(TAG, "onAnimationPause: " );
}
@Override
public void onAnimationResume(Animator animation) {
super.onAnimationResume(animation);
Log.e(TAG, "onAnimationResume: " );
}
});
3.2 AnimatorUpdateListener
监听动画的每一帧,整个动画过程中,每播放一帧,onAnimationUpdate就会被调用一次
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.e(TAG, "onAnimationUpdate: animation.getAnimatedFraction()=="+animation.getAnimatedFraction() );
}
});
4. 工作原理简析与限制条件说明
属性动画要求动画作用的对象提供该属性的get和set方法,然后根据外界传递的初始值和最终值,以动画的效果多次去调用set方法(每次随着时间的推移,传递的值越来越接近最终值),这里延伸出满足动画的生效的两个条件
- object必须提供setXXX方法,如果没有提供初始值还必须提供getXXX方法用于取初始值,如果该条不满足应用会发生崩溃
- object的setXXX方法对属性做出的改变必须能够通过魔种方式反映出来,例如UI上的变化,如果该条不满足应用不会崩溃,但是动画没有效果
上述使用属性动画实现View动画和背景颜色更改动画时,条件1,2都是AndroidSDK本身已经实现了的,因此我们直接进行初始值和结束值的设置启动动画即可,如果我们需要实现的效果或者说要设置的属性没有满足这两个条件时我们可以采取对该对象直接或间接加上get和set方法 ,在set方法中实现属性变换的效果
-
直接或间接设置SET与GET方法
直接设置一般是用在自行定义的对象,确定了属性要实现的效果,这个直接简单,不多叙述
间接设置可以通过对不能直接设置的对象进行指定设置实现,也可以对对象实现不同的动画效果方案从而进行分开管理 -
SET方法中实现属性的改变体现
属性的改变一般可以通过UI上的变化来体现,即在设置属性时要求界面重新绘制,展现出发生的改变,连贯的改变形成了动画的效果。
5. 实现自定义效果
5.1 满足属性动画的限制条件实现效果-- 实现当前界面亮度变换效果
这里可以实现一个随时间变化对当前窗口的屏幕亮度进行一个调节,也是对属性值的一个改变的体现
//定义对象属性及设置对应set、get方法
class Luminance{
float luminanceValue = 100;
public float getLuminanceValue() {
return luminanceValue;
}
public void setLuminanceValue(float luminanceValue) {
Log.e(TAG, "setLuminanceValue: "+luminanceValue );
this.luminanceValue = luminanceValue;
setActivityBrightness(luminanceValue);
}
}
//实现属性的改变体现
/**
* 设置当前Activity亮度
*/
private void setActivityBrightness(float value){
WindowManager.LayoutParams params = getWindow().getAttributes();
params.screenBrightness=value/255; //Activity亮度范围为0-1
getWindow().setAttributes(params);
}
//对该属性设置动画
private void changeScreenLuminance() {
ObjectAnimator animator = ObjectAnimator.ofFloat(new Luminance(), "luminanceValue", 10, 100, 255, 100, 168);
animator.setDuration(9000);
animator.start();
}
5.2 采用ValueAnimator对值进行动画,利用监听实现动画效果--实现当前界面亮度变换效果
使用ValueAnimator直接对值进行变换,不在要求对象提供属性及对应set、get方法,这是因为属性的设置和变换实现均有我们自身去实现了
private void changeScreenLuminanceWithValueAnimator() {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(10, 255);
valueAnimator.setDuration(9000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
FloatEvaluator floatEvaluator = new FloatEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = animation.getAnimatedFraction();
Float evaluate = floatEvaluator.evaluate(fraction, 10, 255);
setActivityBrightness(evaluate);
}
});
valueAnimator.start();
}











网友评论