Property Animation属性动画,通过真实改变Object(可以是View也可以是其他的Object)的属性(只要有setter和getter方法的属性都可以用来制作属性动画)来生成动画(View Animation是通过不断调用View的onDraw方法来生成动画)
用于创建属性动画的三个基本结构类ValueAnimator,ObjectAnimator,AnimatorSet
- 1.ValueAnimator
将初始值和结束值提供给ValueAnimator,并设置时长,系统会自动以给定的速度在每个时间单位中从初始值到结束值之间平滑过渡计算动画值,将这些动画值设置给对象的需要设置动画的属性(通过updatelistener来监听动画值的变化),使得对象的属性值处于一个动态变化的值,不断刷新渲染UI来完成动画
a.在代码中设置ValueAnimator,需要自己将ValueAnimator的值赋给需要变动的属性
有三个计算时间方法(ofFloat()(用于计算浮点数),ofInt()(用于计算整数),ofArgb()(用于计算颜色),前三种已经内建实现了计算更新方法Evaluator,ofObject()(自定义的计算逻辑,需要重写一个类实现TypeEvaluator来实现计算逻辑)
public void startAnimator(){
ValueAnimator animator = ValueAnimator.ofObject(new MyEvaluator(), 0f, 500f);//创建一个ValueAnimator,并设置开始值和结束值,重写一个算法类
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { //为ValueAnimator设置一个值更新监听时间,将值变化赋给需要动态更改的属性
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float i = (float) animation.getAnimatedValue();//得到更新时动画的值
x=i;//将跟新的动画的值赋值给对象的属性上
invalidate(); //不断刷新 UI 达到动画的效果
}
});
animator.setDuration(3000); //设置动画的时间;
animator.start(); //开始动画
}
class MyEvaluator implements TypeEvaluator{ //重写一个算法类继承与TypeEValuator
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) { //重写算法的逻辑
float startFloat = ((Number) startValue).floatValue();
float endFloat = ((Number) endValue).floatValue();
return fraction*(endFloat-startFloat); //可根据需要编写算法,这里是直线的算法
}
}
}
2.ObjectAnimator,是ValueAnimator类的子类,可直接将动画赋值给对象的属性
ObjectAnimator animator = ObjectAnimator.ofObject(imageView/*作用的对象*/, "translationX"/*作用的属性必须有setter和getter方法*/, new MyEvaluator()/*计算的方法*/, 0f/*初始值*/, 300f/*结束值*/);
animator.setDuration(2000);
animator.start();
通过关键帧(KeyFrame)来设置ObjectAnimator
Keyframe kf0 = Keyframe.ofFloat(0f/*前面参数为完成率*/, 0f/*这一完成度时刻的属性值*/);//可以有三种属性值类型 ofFloat,ofInt,ofArgb,根据需要选择
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);//同过PropertyValueHolder来保存属性名,关键帧等信息
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);
3.Animator的速率(interpolator)
interpolator:速率 动画完成的加速度(可以是先加速再减速,先减速再加速,匀速等)
系统内建的interpolator:AccelerateDecelerateInterpolator(先加速再减速 )、AccelerateInterpolator(加速运动)、DecelerateInterpolator(减速运动)、AnticipateInterpolator(先反向运行一段在按照预期的方向急速运动)、AnticipateOvershootInterpolator(先反向运行一段,在按照预期方向运行超过一段,在运行回指定的位置)、BounceInterpolator(弹球跳(落下来会反弹回去再落下来))、CycleInterpolator(向预期方向运行后又回到原地)、LinearInterpolator(线性匀速运动)、OvershootInterpolator(向预期方向运行过头再返回来一段)、
如需自定义速率 则需实现 TimeInterpolator接口
public class MyInterpolator implements TimeInterpolator{
@Override
public float getInterpolation(float input) {
//自己的interpolator代码逻辑
return 0;
}
}
4.AnimatorSet 属性动画集,需要多个属性动画共同完成时使用
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animator1, animator2);//同时播放animator1和animator2;
animatorSet.play(animator2).before(animator3);//animator3之前播放animator2
animatorSet.play(animator2).after(animator4);//zai animator2之后播放animator4;
animatorSet.play(animator4).with(animator5);//同时播放animator4和animator5;
animatorSet.start();//开启属性动画集
5.多个属性动画共同作用时也可以采用 PropertyValuesHolder来代替AnimatorSet
PropertyValuesHolder pvh_width = PropertyValuesHolder.ofFloat("width", ball2.getWidth(), ball2.getWidth() * 2);//将对象的宽度的属性值变化记录下来
PropertyValuesHolder pvh_height = PropertyValuesHolder.ofFloat("height", ball2.getHeight(), ball2.getHeight() * 2);//将对象的高度的属性值变化记录下来
PropertyValuesHolder pvh_x = PropertyValuesHolder.ofFloat("x", ball2.getX(), ball2.getX() - ball2.getWidth() / 2);//将对象的x轴位置的属性变化记录下来
PropertyValuesHolder pvh_y = PropertyValuesHolder.ofFloat("y", ball2.getY(), ball2.getY() - ball2.getWidth() / 2);//将对象在Y轴的位置的属性变化记录下来
ObjectAnimator animator5 = ObjectAnimator.ofPropertyValuesHolder(ball2, pvh_width, pvh_height, pvh_x, pvh_y).setDuration(750);//通过PropertyValueHolder生成多属性同一时间共同变化的ObjectAnimator属性动画
//PropertyValuesHolder还可以通过关键帧来生成
Keyframe k0 = Keyframe.ofFloat(0, balls.get(3).getX());// 当fraction(动画完成度为0时的属性值)
Keyframe k1 = Keyframe.ofFloat(.5f, balls.get(3).getX()+100f);//动画完成度为0.5时的属性值
Keyframe k2 = Keyframe.ofFloat(1, balls.get(3).getX()+50f);//动画完成度为1时的属性值
PropertyValuesHolder pvh_x = PropertyValuesHolder.ofKeyframe("x", k0, k1, k2);
6.属性动画的监听事件
AnimatorListener中包含以下回调监听方法:
onAnimatorStart()
onAnimationEnd()
onAnimationRepeat()
onAnimationCancel()
onAnimationEnd()
通过animator.addListener(new AnimatorListenerAdapter(){});可以通过AnimatorListenerAdapter选择需要监听的事件
ValueAnimator中包含以下回调监听方法:
onAnimationUpdate()//valueAnimator的值更新时会调用,一般在该方法中将animator的值赋给目标对象的属性
通过valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){});注册监听更新事件
7.在XML中定义属性动画 res/animator/下新建xml文件
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially">
<!--set对应代码中的AnimatorSet-->
<objectAnimator
android:duration="1000"
android:repeatCount="2"
android:repeatMode="reverse"
android:valueFrom="1f"
android:valueTo="400f"
android:valueType="floatType"
android:startOffset="1000"
/>
<!--objecAnimator 对应ObjectAnimator-->
<objectAnimator
android:propertyName="translationx"
android:duration="100"
android:valueFrom="1f"
android:valueTo="200f"
android:startOffset="1"
android:repeatMode="restart"
android:repeatCount="2"
android:valueType="floatType"
/>
</set>
将XML中的属性动画在Java代码中实例化
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.myAnimatorSet);//实例化XML中的属性动画
animatorSet.setTarget(imageView);//设置属性动画的目标对象
animatorSet.start();//开启属性动画
8.常用的生成属性动画的view的属性有
translationX(在容器中沿X轴移动) and translationY(在父容器中沿Y轴移动)
rotation(z轴为轴心旋转(既XY都在转)), rotationX(X轴为轴心旋转), rotationY(Y轴为轴心旋转)
scaleX(沿X轴缩放比例小于1为缩小,等于1为不变,大于1为放大) 、 scaleY(沿Y轴缩放比例)
pivotX and pivotY(view旋转或缩放的重心,默认情况下在view的中心位置)
x and y(view在父容器中的(x,y)坐标)
alpha(view的不透明度,0为全透明,1为完全不透明)
9.ViewPropertyAnimator(方便View使用的属性动画类)
view.animate().translationX(300f).translationY(120f);//view同时向X轴移动300f向Y轴移动120f
/*如需要view同时应用好几种属性动画可以应用该方法,将需要变动的属性通过".propertyName(value)"的方式添加在后面*/
button.animate().translationX(300f).translationY(120f).scaleY(2).scaleX(0.8f);