Android的动画组合的实现方式也分视图动画集和属性动画集,视图动画集的实现同样基于XML和代码动态调用的方式,废话不罗嗦能用示例代码看懂的直接上代码:
示例-XML调用方式 定义一个动画集xml文件,test_animator_set.xml
<?xml version="1.0" encoding="utf-8"?>
<set
android:fillAfter="true"
android:duration="3000"
android:shareInterpolator="@android:anim/accelerate_decelerate_interpolator"
xmlns:android="http://schemas.android.com/apk/res/android">
<!--透明度从无到有-->
<alpha android:fromAlpha="0"
android:toAlpha="1"/>
<!--旋转两圈-->
<rotate
android:pivotY="50%"
android:pivotX="50%"
android:fromDegrees="0"
android:toDegrees="720"/>
<!--放大三倍-->
<scale android:pivotX="50%"
android:pivotY="50%"
android:fromXScale="0.1"
android:fromYScale="0.1"
android:toXScale="3"
android:toYScale="3"/>
<!--平移至中间位置-->
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="35%p"
android:toYDelta="42.5%p"/>
</set>
在java代码中调用:
//1.通过xml方式引入动画
Animation animationSet = AnimationUtils.loadAnimation(this,R.anim.test_animator_set);
//设置动画时长为3秒
animationSet.setDuration(3000);
//设置插值器为先加速再减速
animationSet.setInterpolator(new AccelerateDecelerateInterpolator());
//动画完成后保持位置
animationSet.setFillAfter(true);
//开始动画
xxx.startAnimation(animationSet);
代码实现方式:
//2.通过代码生成方式
AnimationSet animationSet = new AnimationSet(true); //true表示共用同一个插值器
//透明度从0至1
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
//旋转两圈
RotateAnimation rotateAnimation = new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//放大三倍
ScaleAnimation scaleAnimation = new ScaleAnimation(0.1f, 3, 0.1f, 3, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//平移距离x方向为父控件宽的35%,y方向为父控件高的42.5%
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.RELATIVE_TO_PARENT, 0.35f, Animation.ABSOLUTE, 0, Animation.RELATIVE_TO_PARENT, 0.425f);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(translateAnimation);
//设置动画时长为3秒
animationSet.setDuration(3000);
//设置插值器为先加速再减速
animationSet.setInterpolator(new AccelerateDecelerateInterpolator());
//动画完成后保持位置
animationSet.setFillAfter(true);
//开始动画
xxx.startAnimation(animationSet);
属性动画集:
属性动画集分为两类,一种是一个对象的多个属性集合,另一个类是多个对象的组合。其中涉及几个重要的类对象:AnimatorSet、ObjectAnimator和PropertyValuesHolder,PropertyValuesHolder在之前的文章已经说过了,在对一个对象的多个属性进行组合动画时可以使用。
对于一个对象的多个属性动画组合可以使用多个AnimatorSet+N个ObjectAnimator对象的方式,也可以使用ObjectAnimator+N个PropertyValuesHolder对象的方式。
对于多个对象的组合则只有使用AnimatorSet+N个ObjectAnimator对象的方式。
AnimatorSet+ObjectAnimator的方式:
//生成一个透明度变化的属性动画对象
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(ibSagiri, "alpha", 0, 0.2f, 0.5f, 1);
//旋转两圈的动画
ObjectAnimator rotationAnimator = ObjectAnimator.ofFloat(ibSagiri, "rotation", 0, 360, 540, 720);
//X轴移动35%父视图的长度
ObjectAnimator translationXAnimator = ObjectAnimator.ofFloat(ibSagiri, "translationX", 0, clParent.getWidth() * 0.35f);
//Y轴移动42.5%父视图的长度
ObjectAnimator translationYAnimator = ObjectAnimator.ofFloat(ibSagiri, "translationY", 0, clParent.getHeight() * 0.425f);
//XY方向都放大3倍
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(ibSagiri, "scaleX", 0, 1, 2, 3);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(ibSagiri, "scaleY", 0, 1, 2, 3);
//生成一个animatorSet对象
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(3000);
animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
//播放多条动画
animatorSet.playTogether(alphaAnimator, rotationAnimator, translationXAnimator, translationYAnimator, scaleXAnimator, scaleYAnimator);
animatorSet.start();
ObjectAnimator+PropertyValuesHolder的方式:
//生成一个透明度变化的valuesHolder,其他同上
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofFloat("alpha", 0, 0.2f, 0.5f, 1);
PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("rotation", 0, 360, 540, 720);
PropertyValuesHolder translationXHolder = PropertyValuesHolder.ofFloat("translationX", 0, clParent.getWidth() * 0.35f);
PropertyValuesHolder translationYHolder = PropertyValuesHolder.ofFloat("translationY", 0, clParent.getHeight() * 0.425f);
PropertyValuesHolder scaleXHolder = PropertyValuesHolder.ofFloat("scaleX", 0, 1, 2, 3);
PropertyValuesHolder scaleYHolder = PropertyValuesHolder.ofFloat("scaleY", 0, 1, 2, 3);
利用多个Holder生成一个ObjectAnimator对象
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(ibSagiri, alphaHolder, rotationHolder, translationXHolder, translationYHolder, scaleXHolder, scaleYHolder);
//设置动画时间
animator.setDuration(3000);
//设置插值器
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.start();
除了上面的用法,Android还提供了一个针对View对象的动画集合用法–View类的animate()方法,该方法之前也提到过的,返回的其实就是ViewPropertyAnimator,这个是Android3.1系统上新增的用法。
ibSagiri.animate()
//.alpha(1) 使用该种方式无法实现透明度的变化
.rotation(720)
.translationX(clParent.getWidth() * 0.35f)
.translationY(clParent.getHeight() * 0.425f)
.scaleX(3).scaleY(3)
.setDuration(3000)
.setInterpolator(new AccelerateDecelerateInterpolator());
这里提一下ViewPropertyAnimator.withStartAction/EndAction()的注意点,
这两个方法是 ViewPropertyAnimator 的独有方法。它们和 set/addListener() 中回调的 onAnimationStart() / onAnimationEnd() 相比起来的不同主要有两点:
withStartAction() / withEndAction() 是一次性的(只会执行一次),在动画执行结束后就自动弃掉了,就算之后再重用 ViewPropertyAnimator 来做别的动画,用它们设置的回调也不会再被调用。而 set/addListener() 所设置的 AnimatorListener 是持续有效的,当动画重复执行时,回调总会被调用。
withEndAction() 设置的回调只有在动画正常结束时才会被调用,而在动画被取消时不会被执行。这点和 AnimatorListener.onAnimationEnd() 的行为是不一致的。
特点:
1、专门针对View对象动画而操作的类。
2、提供了更简洁的链式调用设置多个属性动画,这些动画可以同时进行的。
3、拥有更好的性能,多个属性动画是一次同时变化,只执行一次UI刷新(也就是只调用一次invalidate,而n个ObjectAnimator就会进行n次属性变化,就有n次invalidate)。
4、每个属性提供两种类型方法设置。
5、该类只能通过View的animate()获取其实例对象的引用
缺点:
1.使用该种方式无法实现透明度的变化。
动画组合需要注意的是,如果需要是单次播放,则需要保证组合的动画完全结束,后才可继续播放动画或者先结束当前动画再播放,否则如果依赖于动画事件处理某些问题时会出错。
**
KeyFrame
**
KeyFrame就是关键帧,从电影动画的原理上来说,关键帧就是整个动画过程中,某个特定时刻的画面图像。那么,将这个理解放到属性动画这里,关键帧就是某个特定阶段点的属性值。这里说的阶段点,是指动画完成的进度点。先来看看它的实例化函数
public static Keyframe ofFloat(float fraction, float value)
其中第一个参数fraction,就是进度或者说比例,简单的理解就是动画进行到多少进度时,对应的属性值是多少。
KeyFrame的简单用法如下:
Keyframe frame0 = Keyframe.ofFloat(0f, 0);
Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);
Keyframe frame2 = Keyframe.ofFloat(1, 0);
PropertyValuesHolder frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2);
Animator animator = ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder);
animator.setDuration(1000);
animator.start();
需要说明的是,给PropertyValuesHolder设置KeyFrame对象不能少于两个,只有一个KeyFrame形成不了动画。默认情况下,如代码中的frame0到frame1这段动画中,属性值的变化是匀速的,frame1到frame2这段动画中,属性值的变化也是匀速的。但是这两个速率是不相等的,明显前一段的速率要大一些,后一段的速率要小一些。
下面的小例子,演示了属性动画为ViewGroup的子View的显示和隐藏设置过渡动画:
llImageView = (LinearLayout) root.findViewById(R.id.ll_image);
LayoutTransition transition = new LayoutTransition();
transition.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
transition.setDuration(LayoutTransition.CHANGE_APPEARING, transition.getDuration(LayoutTransition.CHANGE_APPEARING));
transition.setStartDelay(LayoutTransition.CHANGE_APPEARING, 0);
ObjectAnimator appearingAnimator = ObjectAnimator
.ofPropertyValuesHolder(
(Object) null,
PropertyValuesHolder.ofFloat("scaleX", 0.0f, 1.0f),
PropertyValuesHolder.ofFloat("scaleY", 0.0f, 1.0f),
PropertyValuesHolder.ofFloat("alpha", 0, 1.0f));
transition.setAnimator(LayoutTransition.APPEARING, appearingAnimator);
transition.setDuration(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.APPEARING));
transition.setStartDelay(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.CHANGE_APPEARING));
ObjectAnimator disappearingAnimator = ObjectAnimator
.ofPropertyValuesHolder(
(Object) null,
PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.0f),
PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.0f),
PropertyValuesHolder.ofFloat("alpha", 1.0f, 0));
transition.setAnimator(LayoutTransition.DISAPPEARING, disappearingAnimator);
transition.setDuration(LayoutTransition.DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING));
transition.setStartDelay(LayoutTransition.DISAPPEARING, 0);
transition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);
transition.setDuration(LayoutTransition.CHANGE_DISAPPEARING, transition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING));
llImageView.setLayoutTransition(transition);
顺带解释下过渡动画的四种类型CHANGE_APPEARING、APPEARING、DISAPPEARING和CHANGE_DISAPPEARING:
APPEARING
当通过 设置子View的可见性为VISIBLE或者通过addView方法添加子View 来显示子View时,
子View就会执行该类型的动画。
该类型动画的周期为300毫秒,默认延迟为300毫秒。
DISAPPEARING
当通过 设置子View的可见性为GONE或者通过removeView方法移除子View 来隐藏子View时,
子View就会执行该类型的动画。
该类型动画的周期为300毫秒,默认延迟为0毫秒。
CHANGE_APPEARING
当显示子View时,所有的兄弟View就会立即依次执行该类型动画并且兄弟View之间执行动画的间隙默认为0毫秒,然后才会执行显示子View的动画。
该类型动画的周期为300毫秒,默认延迟为0毫秒。
CHANGE_DISAPPEARING
当隐藏子View的动画执行完毕后,所有的兄弟View就会依次执行该类型动画并且兄弟View之间执行动画的间隙默认为0毫秒。
该类型动画的周期为300毫秒,默认延迟为300毫秒。