【Android】组合动画升级

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毫秒。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值