Android 动画机制(二)
属性动画(Property animation)
上一篇文章我们介绍了补间动画,最后我们强调了,补间动画只能改变View的绘制效果,View的真实属性是没有变化的,而属性动画可以直接改变View对象的属性值,属性动画的基类Animator 是一个抽象类,所以我们需要集成这个类,并重写其中的方法,Android SDK默认为开发者提供了几个子类。
属性动画的基本属性:
- android:duration 动画的持续时间
- android:interpolator 动画的插值器
- android:repeatMode 动画重复模式
- android:repeatCount 动画重复次数
- setFrameDelay() 设置刷新率
- set标签 设置动画集合
- android:ordering 动画播放顺序,和set联合使用
AnimatorSet
Animator的子类,用来组合多个Animator,并制定这些Animator 是顺序播放还是同时播放
ValueAnimator
Animator的子类,定义了属性动画的大部分功能,包括计算各个帧的属性值、处理更新事件,按照属性值的类型控制计算规则。’’
ObjectAnimator
ValueAnimator的子类,将属性动画帧的值设置给制定的对象,需要注意,在使用ObjectAnimator时,需要为对象实现setter方法。
如果对象是View ,为了能显示动画效果,在某些情况下需要注册AnimatorUpdateListener监听器,并在回调方法onAnimationUpdate中调用View的invalidate 方法来刷新View的显示。
在代码中的使用方法
ValueAnimator.ofFloat() 和ValueAnimator.ofInt()
//ofint() /ofFloat 创建动画实例,将传入的多个Int参数进行平滑过渡:此处传入0和1,表示将值从0平滑过渡到1
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,1f);
valueAnimator.setDuration(2000);
valueAnimator.setStartDelay(500);//设置动画延迟播放的时间
valueAnimator.setRepeatCount(0);
// ValueAnimator.RESTART(默认):正序重放 ValueAnimator.REVERSE:倒序回放
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
// 设置 值的更新监听器
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float curValue = (Float) animation.getAnimatedValue();
Log.i("PropertyAnimator","curValue=="+curValue);
//重新绘制布局,实现显示效果的改变,本例并不需要调用requestLayout()
view.setScaleX(curValue);
view.requestLayout();
}
});
valueAnimator.start();
XML 配置
<?xml version="1.0" encoding="utf-8"?>
<animator
xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0"
android:valueTo="1000"
android:valueType="intType"
android:duration="1000"
android:repeatCount="0"
android:repeatMode="restart"
android:startOffset="500"
android:fillBefore = "true"
android:fillAfter = "false"
android:fillEnabled= "true"
>
</animator>
相关属性介绍:
android:valueFrom:初始值
android:valueTo:结束值
android:valueType:数据类型
android:duration:动画时长
android:startOffset:执行动画前的延时时长
android:fillBefore:动画播放完成后是否恢复到原来的状态,默认为ture。
android:fillAfter:动画播放完成后是否保持当前的状态,默认为false.
android:fillEnabled:是否开启fillBefore,默认为true
android:repeatCount:重复次数
android:repeatMode:重复模式 restart为正序,reverse为倒序
代码中使用方法:
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.property);
// 设置动画对象
animator.setTarget(imageView);
animator.start();
ValueAnimator.ofObject
ValueAnimator.ofInt和ValueAnimator.ofFloat操作的是int和float类型的数据,而ValueAnimator.ofObject改变的是对象,ValueAnimator.ofObject没有默认的插值器,需要开发者自己去实现TypeEvaluator接口来实现自定义插值器。
这里我们使用前辈们的案列解析:
1.根据需要定义插值器:Point是一个简单的坐标对象,实现set和get方法
public class MyTypeValued implements TypeEvaluator<Point>{
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值
//计算X,Y的差值
float X=endValue.getX()-startValue.getX();
float Y=endValue.getY()-startValue.getY();
//计算当前point的数值,根据自己的实际需要,计算X,Y的值,这里简单的实现匀速平移
//Point point=new Point(fraction*X+startValue.getX(),fraction*Y+startValue.getY());
//模拟抛物线
float x = 400 * (fraction*1.5f); //坐标x = k * t
float y = 400 * (fraction*1.5f) * (fraction*1.5f); //坐标x = k * t *t
Point point=new Point(x,y);
return point;
}
}
动画在自定义View中的使用
public class MyView extends View {
public static final float RADIUS = 100f;// 圆的半径
private Point currentPoint;
private Paint mPaint;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
// 先在初始点画圆,通过监听当前坐标值(currentPoint)的变化,每次变化都调用onDraw()重新绘制圆,从而实现圆的平移动画效果
@Override
protected void onDraw(Canvas canvas) {
if (currentPoint == null) {
currentPoint = new Point(RADIUS, RADIUS);
// 在该点画一个圆
canvas.drawCircle(RADIUS,RADIUS, RADIUS, mPaint);
// 创建初始动画时的对象点 & 结束动画时的对象点
Point startPoint = new Point(RADIUS, RADIUS);// 初始点
Point endPoint = new Point(700, 1000);// 结束点
// 创建动画对象 & 设置初始值 和 结束值
ValueAnimator anim = ValueAnimator.ofObject(new MyEvaluator(), startPoint, endPoint);
anim.setDuration(5000);
//通过 值 的更新监听器,将改变的对象手动赋值给当前对象
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 将每次变化后的坐标值(估值器PointEvaluator中evaluate()返回的Piont对象值)到当前坐标值对象(currentPoint)
currentPoint = (Point) animation.getAnimatedValue();
// 调用invalidate()后,就会刷新View,每次赋值后就重新绘制,从而实现动画效果
invalidate();
}
});
anim.start();
} else {
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
}
}