其中,帧动画因为资源占用大、性能差、内存溢出等不足,已被废弃。
属性动画是Android最常用的动画方案,具有以下优势:
- 动画效果包括但不限于平移、旋转、缩放、透明;
- 作用对象包括但不限于View;
- 同等条件下,属性动画性能&资源占用优于视图动画;
- 高可定制化
2. 原理
ValueAnimator类是通过不断控制 值 的变化,再实时赋给对象,从而实现动画效果
ObjectAnimator类直接改变对象的属性值,从而实现动画效果
3. ValueAnimator使用
ValueAnimator有三个动画构造器方法:(int values)、ofFloat(float values)、ofObject(int values)
三个方法的区别可以理解为只是使用的估值器不一样,原理都是值的改变过程。
属性动画建议以Java动态代码的方式获取动画对象,方便灵活设定值;
3.1 ofFloat
使用浮点型估值器FloatEvaluator ,以float类型的数值,将初始值变化到结束值
public static Animator startValueAnim(float... changeArr ,){
// ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);//从0平滑过渡到1
ValueAnimator anim = ValueAnimator.ofFloat(changeArr);//传入几个就是连续过渡到每个值,直至最后一个值,如0,1,0.8,1
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
}
});
return anim;
}
3.2 ofInt
与ofFloat使用方式一致,ofInt是使用整型估值器IntEvaluator ,以int类型的数值,将初始值变化到结束值
public static Animator startValueAnim(int... changeArr ,){
// ValueAnimator anim = ValueAnimator.ofFloat(0, 100);//从0平滑过渡到100
ValueAnimator anim = ValueAnimator.ofInt(changeArr);//传入几个就是连续过渡到每个值,直至最后一个值,如0,100,20,100
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
}
});
return anim;
}
3.3 ofObject
ofObject可以说是ValueAnimator的核心成员,用法与上述一致,需自定义进度值变化,即编写实现TypeEvaluator类:
public class FloatOutEvaluator implements TypeEvaluator {
/**
*
* @param fraction 进度值
* @param startValue 起始值
* @param endValue 终点值
* @return
*/
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
float cf = fraction;
if (fraction<0.3f){
cf = fraction*2;//前30%进度-进度加倍
}else if (fraction <0.6f){
cf = 0.6f;//暂停一会
}
return startFloat + cf* (((Number) endValue).floatValue() - startFloat);
}
}
使用
ValueAnimator animator = ValueAnimator.ofObject(new FloatOutEvaluator() , 0f,1f);
animator.setDuration(3000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//使用变化值,赋值,刷新,产生动画
view.setAlpha((Float) valueAnimator.getAnimatedValue());
}
});
4. ObjectAnimator
ObjectAnimator 是Android开发实际使用最多的动画,可以直接创建的几种动画及组合动画
4.1 Java代码方式
动画:透明渐变两次
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f, 1f,0f);
animator.setDuration(3000);
animator.start();
同理有:
- 旋转rotation
- 平移translationX、translationY
- 缩放scaleX、scaleY
- 透明变化alpha
4.2 xml方式
属性动画xml资源文件的目录是 res/animator ,与视图动画的资源目录 res/anim不是同一个
举例
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0"
android:valueTo="1.0"
android:valueType="floatType"
android:propertyName="alpha"/>
加载使用动画
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_alpha);
animator.setTarget(view);
animator.start();
同理其他动画rotateion、scale、translate…
4.3 ObjectAnimator扩展 & 自定义TypeEvaluator估值器
扩展“color”动画
1.定义一个View,包含setColor()方法
class ColorTextView extends TextView {
public void setColor(String color){
setTextColor(Color.parseColor(color));
}
public ColorTextView(Context context) {
super(context);
}
public ColorTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
}
2.布局使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.cupster.animation.ColorTextView
android:id="@+id/anim_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试颜色动画的文字"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
3.编写估值器ColorEvaluator,控制颜色随着进度值改变而改变的规则
package com.cupster.animation;
import android.animation.TypeEvaluator;
/**
* 此处代码为郭霖大神编写的自定义Evaluator,用于扩展属性动画:"color",
* 使用该动画的View需设置对应public void setColor,并在其中调用invalidate()
*/
public class ColorEvaluator implements TypeEvaluator {
private int mCurrentRed = -1;
private int mCurrentGreen = -1;
private int mCurrentBlue = -1;
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
String startColor = (String) startValue;
String endColor = (String) endValue;
int startRed = Integer.parseInt(startColor.substring(1, 3), 16);
int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);
int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);
int endRed = Integer.parseInt(endColor.substring(1, 3), 16);
int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);
int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);
// 初始化颜色的值
if (mCurrentRed == -1) {
mCurrentRed = startRed;
}
if (mCurrentGreen == -1) {
mCurrentGreen = startGreen;
}
if (mCurrentBlue == -1) {
mCurrentBlue = startBlue;
}
// 计算初始颜色和结束颜色之间的差值
int redDiff = Math.abs(startRed - endRed);
int greenDiff = Math.abs(startGreen - endGreen);
int blueDiff = Math.abs(startBlue - endBlue);
int colorDiff = redDiff + greenDiff + blueDiff;
if (mCurrentRed != endRed) {
mCurrentRed = getCurrentColor(startRed, endRed, colorDiff, 0,
fraction);
} else if (mCurrentGreen != endGreen) {
mCurrentGreen = getCurrentColor(startGreen, endGreen, colorDiff,
redDiff, fraction);
} else if (mCurrentBlue != endBlue) {
mCurrentBlue = getCurrentColor(startBlue, endBlue, colorDiff,
redDiff + greenDiff, fraction);
}
// 将计算出的当前颜色的值组装返回
String currentColor = "#" + getHexString(mCurrentRed)
+ getHexString(mCurrentGreen) + getHexString(mCurrentBlue);
return currentColor;
}
/**
* 根据fraction值来计算当前的颜色。
*/
private int getCurrentColor(int startColor, int endColor, int colorDiff,
int offset, float fraction) {
int currentColor;
if (startColor > endColor) {
currentColor = (int) (startColor - (fraction * colorDiff - offset));
if (currentColor < endColor) {
currentColor = endColor;
}
} else {
currentColor = (int) (startColor + (fraction * colorDiff - offset));
if (currentColor > endColor) {
currentColor = endColor;
}
}
return currentColor;
}
/**
* 将10进制颜色值转换成16进制。
*/
private String getHexString(int value) {
String hexString = Integer.toHexString(value);
if (hexString.length() == 1) {
hexString = "0" + hexString;
}
return hexString;
}
}
4.封装通用方法
public static void propColorAnimator(ColorTextView target , String startColor , String endColor){
ObjectAnimator animator = ObjectAnimator.ofObject(target ,"color",new ColorEvaluator() ,startColor,endColor);
animator.setDuration(3000);
animator.start();
}
5.使用
tv = findViewById(R.id.anim_view);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
PropAnimatorHelper.propColorAnimator((ColorTextView) view,"#a7dbf7" ,"#ff8696");
}
});