在Android开发过程中,最原始的2种动画分别为补间动画和帧动画,两者存在的弊端都非常明显,补间动画只能由肉眼观察到动画,然而却不能响应点击事件,因为容器并没有移动;帧动画因为需要大量的图片做基础,对内存也是非常大的消耗,因此在项目中都会尽量避免使用帧动画。
在API 3.0之后,出现了第3种动画属性动画,也是当前使用频率最高的动画类型,大部分App中的动画特效均为属性动画制作。
1、属性动画
属性动画解决了补间动画的弊端,容器随着动画的移动而移动,对于任意对象均可设置动画,常用的动画有ValueAnimator
(值动画)、ObjectAnimator
(对象动画),下面的都是这两个重要动画的辅助工具:PropertyValueHolder
(多个动画同时执行)、AnimationSet
(集合动画)、Interpolator
(插值器)、TypeEvaluator
(估值器)
(1)ObjectAnimator
//对象动画,但不局限于对象
ObjectAnimator oa = ObjectAnimator.ofFloat(iv_animation,
"alpha",1.0f,0.4f);
oa.setDuration(3000);
//开启动画
oa.start();
(2)ValueAnimator
这是Android属性动画中最核心的类,通过设置数值完成平滑的匀速移动,通过设置监听得到当前的值,设置给View完成动画的移动。
//值动画
ValueAnimator valueAnimator = ValueAnimator.ofInt(0,100);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取当前动态变化的值
int location = (int) animation.getAnimatedValue();
iv_animation.setX(location);
iv_animation.setY(location);
}
});
//启动动画
valueAnimator.start();
通过设置addUpdateListener
监听,可以使用getAnimatedValue
获取当前移动的距离,设置View的x,y坐标。
除了上述的API之外,还可以设置重复的次数。
//设置重复的次数
valueAnimator.setRepeatCount(2);
valueAnimator.setRepeatCount(ValueAnimator.RESTART);
(3)PropertyValueHolder
//多个动画同时进行
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.3f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.5f);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.5f);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(iv_animation,holder1,holder2,holder3);
objectAnimator.setDuration(3000);
objectAnimator.start();
PropertyValueHolder
是多个动画同时运行,是通过ObjectAnimator
的ofPropertyValuesHolder
来实现,例如上例中,分别3个动画为:清晰度、X轴缩放为原来的一半、Y轴缩放为原来的一半。
和AnimationSet有什么区别呢?
AnimationSet同样也是集合动画,但是AnimationSet更加灵活,可以一起执行,也可以是顺序执行,执行完一个动画之后 就会执行下一个动画。
(4)AnimationSet
ObjectAnimator o1 = ObjectAnimator.ofFloat(iv_animation,"translationX",0f,500f);
ObjectAnimator o2 = ObjectAnimator.ofFloat(iv_animation,"alpha",1.0f,0.5f);
ObjectAnimator o3 = ObjectAnimator.ofFloat(iv_animation,"scaleX",1.0f,1.5f);
AnimatorSet set = new AnimatorSet();
set.setDuration(3000);
set.playSequentially(o1,o2,o3);
set.start();
playSequentially就是按顺序执行,会依次执行完3个动画。
//链式调用
set.play(o3).with(o2).after(o1);
set.play(o3).with(o2).before(o1);
通过链式调用,控制动画的播放顺序,在上述的链式中,就是设计的在o1动画完成之后(或者之前before),o2和o3会一起执行。
set.playTogether(o1,o2,o3);
使用playTogether
就是实现了PropertyValueHolder
的功能,能够实现多个动画的同时执行。
(5)TypeEvaluator(估值器)
对于ValueAnimation
和ObjectAnimation
来说,他们的状态变化是匀速的,等值地变化,因此对于想要实现加速度的效果,例如自由落体,单纯地使用这2种属性动画就比较难了,因此可以使用估值器来完成。
估值器可以自定义动画的变换规则,也可以改变运行轨迹,实现特殊的动画效果
//设计平抛效果
ValueAnimator animator = new ValueAnimator();
animator.setDuration(3000);
//初始坐标为0 0
animator.setObjectValues(new PointF(0,0));
final PointF pointF = new PointF();
animator.setEvaluator(new TypeEvaluator() {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
pointF.x = 100f * (fraction * 5);
pointF.y = 0.5f * 98f * (fraction*5)*(fraction * 5);
return pointF;
}
});
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取估值器中自定义好的对象
PointF location = (PointF) animation.getAnimatedValue();
iv_animation.setX(location.x);
iv_animation.setY(location.y);
}
});
animator.start();
在使用ValueAnimator
时,调用addUpdateListener
,内部其实也有一个估值器,但是这个估值器是匀速的,通过getAnimatedValue
可以得到其中的值,但是要想实现自由落体的效果,匀速的估值器是不可能实现的,平抛水平方向匀速,竖直方向自由落体,因此需要通过setEvaluator
更改估值器,在x和y轴设置,返回Object
对象,在getAnimatedValue
中就可以得到这个PointF
。
(6)Interpolator 插值器
其实插值器和估值器是类似的,唯一的区别在于,估值器的算法需要自己编写,而插值器的算法是由API提供的,大概分为9种。
ValueAnimator v1 = new ValueAnimator();
v1.setDuration(3000);
v1.setObjectValues(new PointF(0,0));
final PointF point = new PointF();
v1.setEvaluator(new TypeEvaluator() {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
point.x = 100f * (fraction * 5);
point.y = 0.5f * 98f * (fraction*5)*(fraction * 5);
return point;
}
});
v1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取估值器中自定义好的对象
PointF location = (PointF) animation.getAnimatedValue();
iv_animation.setX(location.x);
iv_animation.setY(location.y);
}
});
//加速度插值器
v1.setInterpolator(new AccelerateInterpolator(10));
v1.start();
AccelerateInterpolator
:加速插值器,公式: y=t^(2f) (加速度参数. f越大,起始速度越慢,但是速度越来越快;刚开始速度很慢,但是瞬间就下落。)
v1.setInterpolator(new DecelerateInterpolator(5));
DecelerateInterpolator
:减速插值器公式: y=1-(1-t)^(2f) (描述: 加速度参数. f越大,起始速度越快,但是速度越来越慢)
v1.setInterpolator(new AccelerateDecelerateInterpolator());
AccelerateDecelerateInterpolator
:先加速后减速
v1.setInterpolator(new AnticipateInterpolator(tension:8));
AnticipateInterpolator
:张力值,tension值越大,偏移量就越大,而且速度越快。
v1.setInterpolator(new AnticipateOvershootInterpolator(2,3));
public AnticipateOvershootInterpolator() {
mTension = 2.0f * 1.5f;
}
public AnticipateOvershootInterpolator(float tension, float extraTension) {
mTension = tension * extraTension;
}
AnticipateOvershootInterpolator
:张力插值器,类似于抛物线似的,tension和extraTension默认值是2和1.5,值越大,偏移量就越大,速度就越快。
v1.setInterpolator(new BounceInterpolator());
BounceInterpolator
:弹跳插值器
v1.setInterpolator(new CycleInterpolator(2));
CycleInterpolator
:周期插值器,可以设置动画重复的时间周期,类似于repeat
v1.setInterpolator(new LinearInterpolator());
LinearInterpolator
:匀速插值器,这个会屏蔽之前自定义的估值器,而是匀速的完成平抛。
以上就是属性动画中最重要的动画及辅助器,最核心的ValueAnimator类,将会配合估值器和插值器实现多种类型的动画,包括现在的App中,尤其是直播类的App中,观众在发送礼物时,屏幕上会出现该礼物的动画效果,这就涉及到了属性动画的使用,在之后的章节中,将会详细介绍属性动画的高级使用,打造一个动画框架。