在android3.0以前,android的动画机制比较简单,也可以说不健全,那时候是分为两种实现方式:帧动画和补间动画。
1. 帧动画说白了就像gif,在实现的过程中依赖一帧帧的图片资源,然后加载轮播
2. 补间动画倒是可以对view做一些简单的动态效果,但是功能过于简陋,只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,局限性很大。
在3.0之后android提供了一个更加全面和强大的动画实现方式:属性动画。基于此我们可以实现各种各样的动画效果。当然前提你得会用….
属性动画的实现原理其实就是通过对值的不断操作。基于这个实现机制我们就可以在view的外层或内部对view进行持续性的更改操作已完成动画的效果。举个栗子吧:通过以下动画使button的透明度在3秒内从0匀速增至1
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,1f);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
button.setAlpha((float)animation.getAnimatedValue());
}
});
valueAnimator.setDuration(3000);
valueAnimator.start();
当然我们也可以通过setInterpolator()来设置值递增的加速度。
ObjectAnimator是ValueAnimator的子类,也是我们用的比较多的个动画实现类。通过ObjectAnimator我们可以快速的实现上述效果:
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(button, "alpha",0f,1f);
objectAnimator.setDuration(3000);
objectAnimator.start();
这里就表示在3000毫秒内对button的alpha属性进行操作,使其值从0递增到1,从而实现button的透明值渐变动画。这里”alpha”表示对button的alpha属性进行操作,我们还可以传入”rotation”,”translationX”,”translationY”对view的旋转和位移进行动画表示。
有时候单一的属性并不足以支撑我们的动画效果,这时候就需要使用组合动画,组合动画通过AnimatorSet将多个ObjectAnimator动画组合成一个动画集合进行展示。
// 使按钮从左侧进入
ObjectAnimator moveIn = ObjectAnimator.ofFloat(button, "translationX", -500f, 0f);
moveIn.setDuration(2000);
// 使按钮变为透明,再还原
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(button, "alpha",1f,0f,1f);
alphaAnimator.setDuration(3000);
// 使按钮旋转360°
ObjectAnimator rotationAnimator = ObjectAnimator.ofFloat(button, "rotation", 0f, 360f);
rotationAnimator.setDuration(3000);
// 组合上面三个动画
AnimatorSet animators = new AnimatorSet();
animators.play(alphaAnimator).with(rotationAnimator).after(moveIn);
animators.start();
animatorSet有4个方法用以实现动画的组合逻辑,分别是:
1. after(Animator anim) 将现有动画插入到传入的动画之后执行
2. after(long delay) 将现有动画延迟指定毫秒后执行
3. before(Animator anim) 将现有动画插入到传入的动画之前执行
4. with(Animator anim) 将现有动画和传入的动画同时执行
after\before\with不光可以传入单一的属性动画, 也可以传入AnimatorSet组合动画。这样我们就能组合出特殊效果的动画了。
// 垂直方向缩放大小
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(button,"scaleY",1f,3f,1f);
scaleYAnimator.setDuration(3000);
// 组合animators动画集合和scaleYAnaimator
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(animatorSet).with(scaleYAnimator);
animatorSet.start();
我们还可以监听动画在不同的节点的事件并执行相应的处理,比如开始动画、结束动画。Animator总共提供了4个监听事件如下:
animatorSet.addListener(new AnimatorListener() {
// 动画开始时执行
@Override
public void onAnimationStart(Animator animation) {
}
// 动画重复的时候执行
@Override
public void onAnimationRepeat(Animator animation) {
}
// 动画结束的时候执行
@Override
public void onAnimationEnd(Animator animation) {
}
// 动画取消的时候执行
@Override
public void onAnimationCancel(Animator animation) {
}
});
ObjectAnimator和AnimatorSet都是继承自Animator,所以他们都有AnimatorListener监听接口。很多时候我们并不会监听所有的事件,可能只会单独监听开始事件或者结束事件,我们可在这里传入实现了AnimatorListener的抽象类AnimatorListAdapter,然后选择性的实现AnimatorListener的某个或者多个事件。如下:
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// do anything
}
});
Interpolator主要是用来控制动画的变化率的,打个比方说,自由落体运动,刚开始下落的速度为0,但是由于重力加速度导致其下落速度逐渐增大。Interpolator的作用就相当于重力加速度。现有系统提供了以下几种插值器:
1. LinearInterpolator(线性插值器):匀速动画。
2. AccelerateDecelerateInterpolator(加速减速插值器):动画两头慢,中间快。
3. DecelerateInterpolator(减速插值器):动画越来越慢。
4. BounceInterpolator(弹跳插值器):先加速至指向位置,然后反弹数次,逐渐停留至预定目标值。
5. CycleInterpolator(周期插值器):重复动画数次,依照正弦曲线的频率执行。
6. OvershootInterpolator:加速执行,会超出预定目标值,最火回至预定目标值。
7. AnticipateInterpolator:先反向执行,然后加速正向执行至目标值。
8. AnticipateOvershootInterpolator:先反向执行,然后加速正向执行, 会超出预定目标值,最后回至预定目标值。
动画未设置或者传入插值器为空,则默认采用LinearInterpolator插值器。
我们就以最后一个组合的动画为例,采用xml进行编写实现。
xml代码如下:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially" >
<objectAnimator
android:duration="2000"
android:propertyName="translationX"
android:valueFrom="-500"
android:valueTo="0"
android:valueType="floatType" >
objectAnimator>
<set android:ordering="together" >
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" >
objectAnimator>
<set android:ordering="sequentially">
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" >
objectAnimator>
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" >
objectAnimator>
set>
set>
<objectAnimator
android:duration="1500"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="3"
android:valueType="floatType" >
objectAnimator>
<objectAnimator
android:duration="1500"
android:propertyName="scaleY"
android:valueFrom="3"
android:valueTo="1"
android:valueType="floatType" >
objectAnimator>
set>