简单的属性动画的实现
现在设计一个动画,让View从x坐标50处移动到x坐标400处
使用ValueAnimator的实现
public void startObjectAnimatorAnim(final View v) {
ValueAnimator animator = ValueAnimator.ofFloat(50, 400);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
v.setTranslationX(value);
}
});
animator.setDuration(1000);
animator.start();
}
ValueAnimaotr是最直接的属性动画的使用方式,ValueAnimator还有个子类ObjectAnimator
ObjectAnimator的实现
public void startObjectAnimatorAnim(View v) {
ObjectAnimator animator = ObjectAnimator.ofFloat(v, "translationX", 50, 400);
animator.setDuration(1000);
animator.start();
}
非常简单的几行代码即可实现一个View的平移动画。同理,传递不同的属性和值,也会实现该View针对不同的属性的变化
ofFloat第一个参数是需要进行动画的对象,第二个参数为该对象所支持的属性,后面为可变参数,传递的是该属性的值
这里可能会有同学问第二个参数的取值有什么规则么?这里第二个参数的传值,跟第一个参数的类型有关系,这个我们后面分析源码时会讲
使用PropertyValueHolder实现
public void startObjectAnimatorAnim(final View v) {
PropertyValuesHolder holder = PropertyValuesHolder.ofFloat("translationX", 40, 500);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(v, holder);
animator.setDuration(1000);
animator.start();
}
效果图:
42008ac2ae0b2d8e979e805ad52fe09e[00_00_00--00_00_04].gif
动画组合效果的实现
现在我们让View从50移动到400处时,透明度从100%逐渐变化到0%
使用ValueAnimator实现
ValueAnimator animator = ValueAnimator.ofFloat(0, 1f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
float translationX = 50 + 350 * value;
float alpha = 1 - value;
v.setTranslationX(translationX);
v.setAlpha(alpha);
}
});
animator.setDuration(1000);
animator.start();
使用PropertyValueHolder实现:
public void startObjectAnimatorAnim(final View v) {
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofFloat("alpha", 1f, 0f);
PropertyValuesHolder translationHolder = PropertyValuesHolder.ofFloat("translationX", 50, 400);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(v, alphaHolder, translationHolder);
animator.setDuration(1000);
animator.start();
}
如果使用ObjectAnimator单独指定属性的方式,因为属性不能设置多个,所以不能满足需求,如想要实现,可借助AnimatorSet:
AnimatorSet实现
public void startObjectAnimatorAnim(final View v) {
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(v, "alpha", 1, 0);
alphaAnim.setDuration(1000);
ObjectAnimator translationAnim = ObjectAnimator.ofFloat(v, "translationX", 50, 400);
translationAnim.setDuration(1000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(1000);
//animatorSet.playTogether(alphaAnim, translationAnim);
animatorSet.play(alphaAnim).with(translationAnim);
animatorSet.start();
}
AnimatorSet的其他常用方法:
- animatorSet.play(animator1).with(animator2);动画1和动画2同时执行
- animatorSet.play(animator3).after(animator2);动画3在动画2执行完成后执行
- animatorSet.playSequentially(animator1,animator2,animator3)动画1,2,3按顺序执行
-
animatorSet.playTogether(animator1,animator2,animator3)三个动画同时执行
效果图:
translation_alpha.gif
可以看到,ValueAnimator需要我们手动去计算值,这种方式更加繁琐确更加灵活,而使用ObjectAnimator直接指定属性和ObjectAnimator指定PropertyValueHolder的最终实现其实是一样的,这个我们先不讲,后面分析
差值器
新年又有新规定,现在要求小球做加速运动从50移动到400,因为动画默认是匀速的,想做加速运动就必须要借助差值器(Interpolator)了
Interpolator负责控制动画变化的速率,使得基本的动画效果能够以匀速、加速、减速、抛物线速率等各种速率变化。
动画的每一帧都将在开始和结束之间的特定时间显示,此时动画时间被转换为时间索引,则动画时间轴上的每个点都可以转换成0.0到1.0之间的一个浮点数。然后再将该值用于计算该对象的属性变换
下面我们看一下加速动画的代码实现,因为这几种属性动画的实现都类似,我们接下来只演示ValueAnimator的实现
代码:
public void startObjectAnimatorAnim(final View v) {
ValueAnimator animator = ValueAnimator.ofFloat(40, 500);
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
v.setTranslationX(value);
}
});
animator.setDuration(2000);
animator.start();
}
这里只比上面的实现增加了一句animator.setInterpolator(new AccelerateInterpolator());
这句话的意思是在这个动画里增加了一个差值器,这个差值器的作用是将动画做加速运动
这个AccelerateInterpolator是Android系统实现好的差值器,其它系统实现的差值器还有
//加速查值器,参数越大,速度越来越快
animator.setInterpolator(new AccelerateInterpolator(10));
//减速差值起,和上面相反
animator.setInterpolator(new DecelerateInterpolator(10));
//先加速后减速差值器
animator.setInterpolator(new AccelerateDecelerateInterpolator());
//张力值,默认为2,T越大,初始的偏移越大,而且速度越快
animator.setInterpolator(new AnticipateInterpolator(3));
//张力值tension,默认为2,张力越大,起始时和结束时的偏移越大
animator.setInterpolator(new AnticipateOvershootInterpolator(6));
//弹跳差值器
animator.setInterpolator(new BounceInterpolator());
//周期差值器
animator.setInterpolator(new CycleInterpolator(2));
//线性差值器,匀速
animator.setInterpolator(new LinearInterpolator());
自定义差值器
上面又来了规定中的规定,要求View运动时,前半段时间匀速,后半段时间加速,目前系统实现的差值器没有这种效果,这样就需要我们自己定义差值器了
要自定义差值器也比较简单,只需要实现TimeInterpolator接口,并重新实现TimeInterpolator的getInterpolation即可 getInterpolation的入参就是在匀速状态下动画的完成度,我们针对入参做一些更改,即可实现各种各样的动画效果
看下代码实现:
public void startObjectAnimatorAnim(final View v) {
ValueAnimator animator = ValueAnimator.ofFloat(40, 500);
animator.setInterpolator(new CustomInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
v.setTranslationX(value);
}
});
animator.setDuration(2000);
animator.start();
}
// 自定义差值器 CustomInterpolator .java
public class CustomInterpolator implements TimeInterpolator {
@Override
public float getInterpolation(float input) {
if (input < 0.5f) {
return input / 2;
}
return input * input;
}
}
看下效果:
custom_interpolator.gif
估值器
上面的规定越来越多,要求View运动时,前半段时间匀速,后半段时间加速,在到达400位置后,要有惯性效果,即超出一部分(假设运动到430位置)再弹回
我们现在分析一下这种场景,如果想要到达位置后有个超出的效果,继续在CustomInterpolator基础上修改差值器逻辑会有些复杂,这个时候,可以自定义一个估值器来实现
估值器是什么
如果说差值器是动画在时间维度的变化的话,那么估值器就是动画在数值维度上的变化,其实差值器和估值器是配合使用的,如果我么什么也不操作,系统也会给我们默认生成一个差值器和估值器,而估值器用来计算的参数,也是通过差值器的计算给出的,这个我们后面分析源码的时候再讲
下面我们看一下如何使用估值器实现上述效果
自定义差值器的实现也很简单,只需要实现TypeEvaluator即可:
/*** CustomEvaluator.java */
public class CustomEvaluator implements TypeEvaluator<Float> {
@Override
public Float evaluate(float fraction, Float startValue, Float endValue) {
if (fraction <= 0.8) {
// 动画执行的前80% 走完全部路径
return startValue + (endValue - startValue) / 0.8f * fraction;
} else if (fraction <= 0.9) {
// 动画执行的80%-90%时走到430处
return endValue + 30 * (fraction - 0.8f) / 0.1f;
} else {
// 动画执行的90%-100%时返回400处
return endValue + 30 - 30 * (fraction - 0.9f) / 0.1f;
}
}
}
/**** MainActivity */
public void startObjectAnimatorAnim(final View v) {
ValueAnimator animator = ValueAnimator.ofObject(new CustomEvaluator(), 50f, 400f);
animator.setInterpolator(new CustomInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
v.setTranslationX(value);
}
});
animator.setDuration(2000);
animator.start();
}
效果图:
type_evaluator.gif
关键帧
上面的规定没完没了,现在要求View从50匀速移动到400,在动画运行的前半段透明度为100% 后半段从100%变为0%
我们一看,哦 上面的规定也蛮简单的嘛,通过ValueAnimator AnimatorSet 这不都能做么 有没有其他办法呢?
我们来尝试一下新方案
public void startObjectAnimatorAnim(final View v) {
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofFloat("alpha", 1f, 1f, 0f);
PropertyValuesHolder translationHolder = PropertyValuesHolder.ofFloat("translationX", 50, 400);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(v, alphaHolder, translationHolder);
animator.setDuration(1000);
animator.start();
}
效果图:
key_frame.gif
这里和上面那个案例唯一的区别就是alphaHolder可变参数那里,上面的案例可变参数是2个,这里变成了三个,这里每一个参数都是一个关键帧,它们用来标记动画执行的不同阶段,通过关键帧,我们可以做的变换有多了一些
以上就是属性动画的常用方式和方法,使用起来还是比较简单的,而且功能也比较强大,反正我是比较喜欢用属性动画去实现一些UI效果的
网友评论