属性动画与补间动画最大的区别就是,控件通过属性动画改变位置后,控件的位置会随着改变,而补间动画控件还是在原地。
属性:
Duration:动画持续时间,默认持续时间为300ms
Time Interpolation:时间差值,与补间动画的Interpolation相似,即改变动画执行速度
Repeat count and behavior:重复次数及模式
Animator sets:动画集合
Frame refresh delay:多久刷新一次帧,默认10ms,依赖系统执行的状态
相关类:
ObjectAnimator:动画的执行类
ValueAnimator:动画的执行类
AnimatorSet:动画集合
AnmatorInflater:加载文件夹为animator的xml文件
TypeEvaluator:类型估值,主要用于设置动画操作属性的值
TimeInterpolator:时间差值
以下是代码的应用:
package com.example.propertyanimation;
import android.os.Bundle;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.IntEvaluator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.PointF;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
@SuppressLint("NewApi")
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* xml绑定标签
* @param v
* x方向上旋转的动画效果
*/
public void a(View v) {
//属性动画的动画执行类
/**
* @parm target-->要操作的属性的对象(如果为T类型则是泛型,Object所有类型)
* @parm property-->要操作的属性的名称,即v对象的set方法中的属性都可以改变
* @parm values-->改变该属性的值
*/
ObjectAnimator animator = ObjectAnimator.ofFloat(v, "rotationX", 0,360.0f,0);//从0-->360-->0
animator.setDuration(3000);//执行时间
animator.start();//启动动画
}
/**
* 同时设置多个属性的动画效果
* 透明度从0到1,拉伸从0到1再拉伸到2倍(变化的趋势一样)
*/
public void b(final View v) {
/*
* 方法1
*/
// ObjectAnimator animator = ObjectAnimator.ofFloat(v, "", 0,1);
// animator.setDuration(5000);
// animator.start();
// //添加在更新时的监听事件
// animator.addUpdateListener(new AnimatorUpdateListener() {
// //每次动画刷新的时候就会执行该方法
// @Override
// public void onAnimationUpdate(ValueAnimator arg0) {
// //此次刷新时改变的值
// float value = (Float) arg0.getAnimatedValue();
// v.setAlpha(value);
// float scaleX = 2 * value;//拉伸到2倍
// v.setScaleX(scaleX);
// v.setScaleY(scaleX);
// }
// });
/*
* 方法2
*/
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 0,2);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 0,2);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 0,1);
//同时在v上设置三个动画效果,参数2为可变参数
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(v, holder1,holder2,holder3);
animator.setDuration(5000);
animator.start();
}
/**
* 设置控件的宽高
*/
public void c(final View v) {
// Button button;
// button.setWidth(pixels)//不是设置控件宽度,是设置控件的最大宽度
ObjectAnimator animator = ObjectAnimator.ofFloat(v, "", 0, 200);
animator.setDuration(4000);
animator.start();
//若改变的属性没有set方法,可以在监听事件中进行修改
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
float value = (Float) arg0.getAnimatedValue();
/**
* 改变控件的宽高
*/
//获取布局参数
LayoutParams params = v.getLayoutParams();//统一的父类ViewGroup,所以不用强转
params.width = (int) value;
params.height = (int) value;
v.requestLayout();//请求布局,刷新布局参数,一般使用这个。只要布局改变了调用这个方法都有效果
// v.setLayoutParams(params);
}
});
}
/**
* 使用类型估值(TypeValue)设置控件的宽高
*/
public void d(final View v) {
final int width = v.getWidth();
ObjectAnimator animator = ObjectAnimator.ofFloat(v, "", 1, 100);
animator.setDuration(4000);
animator.start();
//若改变的属性没有set方法,可以在监听事件中进行修改
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
float value = (Float) arg0.getAnimatedValue();//获取每次改变的值
// FloatEvaluator
IntEvaluator intEvaluator = new IntEvaluator();//获取类型估值对象
/**
* 改变控件的宽高
*/
//获取布局参数
LayoutParams params = v.getLayoutParams();//统一的父类ViewGroup,所以不用强转
//每次改变的值为:(200-width)/100
//方法1
// params.width = (int) (width + value*(200-width)/100);//目的:每次变化的值都一样,不管控件的大小是多少
//参数1每次改变的值(每次改变的比例),参数2为起始的值,参数3为结束的值
//参数1已经写好了:(结束的值-起始的值)*value
params.width = intEvaluator.evaluate(value/100, width, 200);
params.height = (int) value;
v.requestLayout();
}
});
}
/**
* 类型估值的应用
*/
public void e(final View v) {
//让控件随着设置的点移动,PointF浮点数坐标
TypeEvaluator<PointF> evaluator = new TypeEvaluator<PointF>() {
/**
* 估算每次移动时的位置
* @param arg0 -->此次变化的比例
* @param arg1 -->最开始的时候的位置
* @param arg2 -->最后的位置
* @return
*/
@Override
public PointF evaluate(float arg0, PointF arg1, PointF arg2) {
PointF pointF = new PointF();
pointF.x = (arg2.x-arg1.x)*arg0+arg1.x;
pointF.y = (arg2.y-arg1.y)*arg0+arg1.y;
return pointF;
}
};
PointF start = new PointF(v.getLeft(), v.getTop());//起始的位置
PointF end = new PointF(200, 200);//结束的位置
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(v, "", evaluator, start,end);
objectAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
PointF pointF = (PointF) arg0.getAnimatedValue();
v.setX(pointF.x);
v.setY(pointF.y);
}
});
objectAnimator.setDuration(1000);
objectAnimator.start();
}
/**
* ValueAnimtor
*/
public void f(final View v) {
ValueAnimator animator = new ValueAnimator();
//设置动画变化的值
animator.setFloatValues(0,360,0);
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
v.setRotationX(value);
}
});
animator.setDuration(1000);
animator.start();
}
/**
* 监听动画状态
*/
public void g(View v) {
ValueAnimator valueAnimator = new ValueAnimator();
// valueAnimator.cancel();//取消动画
/**
* 状态变化时就会执行
*/
valueAnimator.addListener(new AnimatorListener() {
//开始动画的状态
@Override
public void onAnimationStart(Animator animation) {
}
//重复的状态
@Override
public void onAnimationRepeat(Animator animation) {
}
//动画结束的时候
@Override
public void onAnimationEnd(Animator animation) {
}
//动画取消的状态,即调用cancel()方法时才会调用
@Override
public void onAnimationCancel(Animator animation) {
}
});
/**
* 监听动画的状态
* 添加AnimatorListenerAdapter监听事件,按照需要重写需要监听的动画状态的方法
*/
//AnimatorListenerAdapter抽象类,方法都已经重写,但是方法体都是空的
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
});
}
/**
* AnimatorSet
* 动画的集合
*/
public void h() {
ValueAnimator v1 = new ValueAnimator();
ValueAnimator v2 = new ValueAnimator();
ValueAnimator v3 = new ValueAnimator();
AnimatorSet animatorSet = new AnimatorSet();
//播放v1和v2一起
animatorSet.play(v1).with(v2);
//播放v3在v2之后
animatorSet.play(v3).after(v2);
//全部一起播放
animatorSet.playTogether(v1,v2,v3);
//按顺序播放,写前面的先播放
animatorSet.playSequentially(v1,v2,v3);
//每一个动画执行的时间
animatorSet.setDuration(1000);
animatorSet.start();
}
/**
* xml中设置属性动画
*/
public void i(View v) {
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.object);
//设置操作的控件
animator.setTarget(v);
animator.start();
}
}
xml文件如下:
值得注意的是属性动画的res下的文件夹应该是animator
<?xml version="1.0" encoding="utf-8"?>
<!--propertyName:属性 -->
<!--valueType:变化值的类型 -->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="360"
android:propertyName="rotationX">
</objectAnimator>