属性动画
所谓属性动画,就是改变对象Object的属性来实现动画过程。属性动画是对View的动画的扩展,通过它可以实现更多漂亮的动画效果。同时属性动画的作用对象不仅仅是View,任何对象都可以。
属性动画的作用效果就是:在一个指定的时间段内将对象的一个属性的属性值动态地变化到另一个属性值。
ObjectAnimator
ObjectAnimator
.ofFloat(mImageView, "rotationY", 0f, 360f)
.setDuration(2000)
.start();
ObjectAnimtor可以用ofInt、ofFloat、ofObject等静态方法,传入动画作用的目标Object、属性字段、属性开始值、属性中间值、属性结束值等参数来构造动画对象。 通过不断去调用对象属性的setter方法改变属性值,不断重绘实现动画过程.
xml实现属性动画,工程的res目录下创建animator文件,创建xml文件
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:propertyName="rotationY"
android:valueFrom="0"
android:valueTo="360"
//类型
android:valueType="floatType">
</objectAnimator>
private void startXmlPropertyAnimator() {
Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(),R.animator.property_animator);
animator.setTarget(mImageView);
animator.start();
}
当然也可以通过动画组合的形式来执行多个动画。AnimationSet
Animator scaleXAnimator = ObjectAnimator.ofFloat(mImageView, "scaleX", 1, 0.5f);
scaleXAnimator.setDuration(2000);
Animator scaleYAnimator = ObjectAnimator.ofFloat(mImageView, "scaleY", 1, 0.5f);
scaleYAnimator.setDuration(2000);
Animator rotationXAnimator = ObjectAnimator.ofFloat(mImageView, "rotationX", 0, 360);
rotationXAnimator.setDuration(2000);
Animator rotationYAnimator = ObjectAnimator.ofFloat(mImageView, "rotationY", 0, 360);
rotationYAnimator.setDuration(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(scaleXAnimator)
.with(scaleYAnimator)
.before(rotationXAnimator)
.after(rotationYAnimator);
animatorSet.start();
AnimatorSet通过before、with、after三个方法可以组合多个属性动画,with表示与给定动画同时执行,before在给定动画执行之前执行,after表示在给定动画执行之后执行.
属性动画也可以在xml定义动画集
ValueAnimator
ValueAnimator是ObjectAnimator的父类,它继承自Animator。ValueAnimaotor同样提供了ofInt、ofFloat、ofObject等静态方法,传入的参数是动画过程的开始值、中间值、结束值来构造动画对象。可以将ValueAnimator看着一个值变化器,即在给定的时间内将一个目标值从给定的开始值变化到给定的结束值。在使用ValueAnimator时通常需要添加一个动画更新的监听器,在监听器中能够获取到执行过程中的每一个动画值。ValueAnimator的使用一般会结合更新监听器AnimatorUpdateListener,大多数时候是在自定义控件时使用。
下面看个列子
当点击箭头,会展开文本内容,当然同时伴随着动画出现。
private void anim() {
// 指示器旋转
ValueAnimator valueAnimator1 = isClosed
? ValueAnimator.ofFloat(180, 0)
: ValueAnimator.ofFloat(0, 180);
valueAnimator1.setDuration(500);
valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
mIvIndicator.setRotation(value);
}
});
valueAnimator1.start();
// 打开开关闭操作
// 内容的高度
final int answerHeight = mTvAnswer.getMeasuredHeight();
ValueAnimator valueAnimator2 = isClosed
? ValueAnimator.ofInt(-answerHeight, 0)
: ValueAnimator.ofInt(0, -answerHeight);
valueAnimator2.setDuration(500);
final MarginLayoutParams params = (MarginLayoutParams) mTvAnswer.getLayoutParams();
valueAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 接收内容的高度
int value = (int) animation.getAnimatedValue();
params.bottomMargin = value;
// 设置高度变化
mTvAnswer.setLayoutParams(params);
}
});
valueAnimator2.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
//记录动画结束的状态
isClosed = !isClosed;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator2.start();
}
TypeEvaluator
属性动画计算器。ObjectAnimator和ValueAnimator都有ofObject方法,传入的都有一个TypeEvaluator类型的参数.TypeEvaluator是一个接口,有个方法avaluate
public T evaluate(float fraction, T startValue, T endValue);
要用属性动画来执行复杂对象的动画过程,就需要自定义TypeEvaluator,实现动画逻辑。
public class Circle {
private int raduis; // 半径
private int color; // 颜色
private int elevation; // 高度
public Circle(int raduis, int color, int elevation) {
this.raduis = raduis;
this.color = color;
this.elevation = elevation;
}
public int getRaduis() {
return raduis;
}
public void setRaduis(int raduis) {
this.raduis = raduis;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getElevation() {
return elevation;
}
public void setElevation(int elevation) {
this.elevation = elevation;
}
}
自定义控件CircleView,将Circle作为它的一个属性:
public class CircleView extends View {
private Circle circle;
private Paint mPaint;
public CircleView(Context context, AttributeSet attrs) {
super(context, attrs);
circle = new Circle(168, Color.RED, 0);
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setElevation(circle.getElevation());
mPaint.setColor(circle.getColor());
canvas.drawCircle(getMeasuredHeight() / 2, getMeasuredHeight() / 2, circle.getRaduis(), mPaint);
}
public void setCircle(Circle circle) {
this.circle = circle;
postInvalidate();
}
public Circle getCircle() {
return circle;
}
}
方法的调用,创建三个圆,由半径168到300到450依次执行,当然还有颜色的变化,红色-绿色-蓝色,高度的变化。
ObjectAnimator使用:注意属性动画是通过反射获取,所以属性的名字是circle
private void start1() {
Circle startCircle = new Circle(168, Color.RED, 0);
Circle middleCircle = new Circle(300, Color.GREEN, 15);
Circle endCircle = new Circle(450, Color.BLUE, 30);
ObjectAnimator.ofObject(mCircleView, "circle", new CircleEvaluator(), startCircle, middleCircle, endCircle)
.setDuration(5000)
.start();
}
ValueAnimator使用:
private void start2() {
Circle startCircle = new Circle(168, Color.RED, 0);
Circle middleCircle = new Circle(300, Color.GREEN, 15);
Circle endCircle = new Circle(450, Color.BLUE, 30);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new CircleEvaluator(), startCircle, middleCircle, endCircle);
valueAnimator.setDuration(5000);
//通过监听变化,给view赋值
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Circle circle = (Circle) animation.getAnimatedValue();
mCircleView.setCircle(circle);
}
});
valueAnimator.start();
}
该文摘自:https://juejin.im/entry/58b3f07e570c35006932b067