欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

安卓动画学习(五)--组合属性动画

程序员文章站 2022-05-03 10:36:39
...

安卓动画学习--组合属性动画

  • 上篇我们知道PropertyValuesHolder是用来包装一个单系列动画的,那么通过ObjectAnimator.ofPropertyValuesHolder()这个方法,我们可以实现组合动画,不过这个方法来控制动画终究是麻烦了点
  • 所以官方还根据补间动画那样子给我们提供了一个组合动画的类AnimatorSet,通过这个类我们可以很方便的控制组合动画当中单个动画的具体动作,一起来学习一下吧

AnimatorSet

  • 先来看一下官方文档
  • This class plays a set of Animator objects in the specified order. Animations can be set up to play together, in sequence, or after a specified delay.
  • There are two different approaches to adding animations to a AnimatorSet: either the playTogether() or playSequentially() methods can be called to add a set of animations all at once, or the play(Animator) can be used in conjunction with methods in the Builder class to add animations one by one.
  • It is possible to set up a AnimatorSet with circular dependencies between its animations. For example, an animation a1 could be set up to start before animation a2, a2 before a3, and a3 before a1. The results of this configuration are undefined, but will typically result in none of the affected animations being played. Because of this (and because circular dependencies do not make logical sense anyway), circular dependencies should be avoided, and the dependency flow of animations should only be in one direction.
  • 英文好的同学可以自行翻译,我这个渣渣还是看的谷歌翻译,假装自己看懂,他的大概意思是
  • 这个类可以以指定的规则或者顺序播放一组动画
  • 有两种方法可以将动画添加到set中去,调用playTogether()or playSequentially()方法来一次添加一组动画,或者play(Animator)可以与Builder 类中的方法一起使用以逐个添加动画
  • 可以设置动画之间的链接规则,比方说定义动画a1在a2之后播放,但通常不建议这样做,还是来看看具体用法吧

添加动画到set

先来看第一种

  • 第一种有两个方法playSequentially和playTogether
  • 先看第一个
playSequentially(List<Animator> items)//设置此AnimatorSet以在上一个动画结束时播放每个提供的动画。
playSequentially(Animator... items)//设置此AnimatorSet以在上一个动画结束时播放每个提供的动画。
  • 嗯,大概意思就是他会依次播放每个动画,第一个直接传一个list第一个是一个变长参数,归根结底都一样的,在添加的时候都是有先后顺序的,播放的话到时候就会按照先后顺序依次播放
  • 再看第二个
playTogether(Collection<Animator> items)//设置此AnimatorSet可同时播放所有提供的动画。
playTogether(Collection<Animator> items)//设置此AnimatorSet可同时播放所有提供的动画。
  • 一起播放所有动画,没啥说的
  • 注意,这里有一点需要注意,我们知道动画可以设置重复次数,还可以设置无限重复,但是,如果将无限重复的动画用第一种方法添加的话,那么这个动画之后的动画就永远没有机会执行了,如下
ObjectAnimator tv1TranslateY = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 300, 0);
tv1TranslateY.setRepeatCount(ValueAnimator.INFINITE);

ObjectAnimator tv2TranslateY = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(tv1BgAnimator,tv1TranslateY,tv2TranslateY);
animatorSet.setDuration(2000);
animatorSet.start();
  • 这样开始的动画他的第三个动画是永远得不到执行的,而在第二个方法中我们是可以设置无限重复的,因为他是所有动画一起执行的

第二种--更牛逼的组合动画的方式

  • 在AnimatorSet中有一个内部类,他也可以实现将动画组合,看一下吧
AnimatorSet.Builder//Builder对象是一个实用程序类,以便于将动画添加到 AnimatorSet各种动画之间的关系中。 
  • 看一下怎么用吧
  • 安卓并没有为我们提供构造器去创建一个实例内部类
  • 而在一个play方法里面却是返回了一个内部类实例
public Builder play(Animator anim) {
        if (anim != null) {
            return new Builder(anim);
        }
        return null;
    }
  • 在内部类当中为我们提供了这些方法
  • 注意,这些方法是在play方法之后才能调用的,而play方法传入的是一个Animator
方法名 用法
AnimatorSet.Builder after(long delay) 在延时一段时间之后运行play中的方法
AnimatorSet.Builder after(Animator anim) 在这个动画之后运行play中的方法
AnimatorSet.Builder before(Animator anim) 在play中的动画播放完成之后播放
AnimatorSet.Builder with(Animator anim) 与play中的动画同时播放
  • 注意,方法名的之前之后是play中的动画相对于以上方法中的动画的,下面给个实例说明
Button button = findViewById(R.id.main_useAnimatorSetBt);
        ImageView imageView = findViewById(R.id.main_useAnimatorSetIv);
        ObjectAnimator animator = ObjectAnimator.ofFloat(imageView,"translationY",0,800,400,600);
        animator.setDuration(1000);
        ObjectAnimator animator2 = ObjectAnimator.ofArgb(button,"backgroundColor",Color.RED,Color.GREEN,Color.BLUE);
        animator2.setDuration(2000);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView,"translationX",0,300,150,350);
        animator1.setDuration(2000);
        
        final AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animator).after(1000);
        animatorSet.play(animator2).after(animator);
        animatorSet.play(animator1).with(animator2);
        
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                animatorSet.start();
            }
        });
  • 前面创建动画部分不用说,我们来分析加入动画部分
  • 第一句,animator在延时1000毫秒播放
  • 第二句,animator2在animator之后播放
  • 第三句,animator1与animator2同时播放
  • 相信这样分析读者很容易看出动画之间的关系,如果这样还有点困难,那我们来点暴躁的
animatorSet.play(animator1).with(animator2).after(animator).after(1000);
  • 把刚才的三句话改成一句话
  • 理解的时候直接从后往前,ok,这下粗暴理解了吧
  • 先延时,再animator,再animator2和animator1同时,可以了吧
  • 至于还有第三种
AnimatorSet.Builder builder = animatorSet.play(animator1);
        builder.with(animator2);
        builder.after(animator);
        builder.after(1000);
  • 这样还是得逆向思维,先进行最下面的1000ms,再animator,再animator2和animator1
  • 这种就不具体分析了,看个人理解使用吧
  • 官方示例代码是第一种,不过我觉得第二种反倒更容易理解,这个因人而异吧

我们还可以为animatorSet添加事件监听器

public void addListener(AnimatorListener listener);
public static interface AnimatorListener {
    /**
     * AnimatorSet开始时调用
     */
    void onAnimationStart(Animator animation);

    /**
     * AnimatorSet结束时调用
     */
    void onAnimationEnd(Animator animation);

    /**
     * AnimatorSet被取消时调用
     */
    void onAnimationCancel(Animator animation);

    /**
     * AnimatorSet重复时调用,由于AnimatorSet没有设置repeat的函数,所以这个方法永远不会被调用
     */
    void onAnimationRepeat(Animator animation);
}
  • 先来看一下常用方法吧,想了解更多的同学可以去看官方文档
方法名 用法
void cancel() 取消AnimatorSet它所负责的所有动画
void end() 结束AnimatorSet它所负责的所有动画。
long getCurrentPlayTime() 返回自动画开始以来经过的毫秒数。
long getDuration() 获取此AnimatorSet的每个子动画的长度。
TimeInterpolator getInterpolator() 返回此动画使用的定时插补器。
long getStartDelay() start()调用之后延迟启动动画的时间量(以毫秒为单位)
long getTotalDuration() 获取动画的总持续时间,计算动画序列,启动延迟和重复。
boolean isRunning() 如果此AnimatorSet的任何子动画已启动且尚未结束,则返回true。
boolean isStarted() 返回此Animator是否已启动且尚未结束。
void pause() 暂停正在运行的动画。
void resume() 当被pause时可以调用
void reverse() 反向播放AnimatorSet的动画集
void setCurrentPlayTime(long playTime) 将动画的位置设置为指定的时间点。
AnimatorSet setDuration(long duration) 设置此AnimatorSet的每个当前子动画的长度。
void setInterpolator(TimeInterpolator interpolator) 为此AnimatorSet的所有动画设置TimeInterpolator 。
void setStartDelay(long startDelay) start()调用之后延迟启动动画的时间量(以毫秒为单位) 。
void setTarget(Object target) 设置此AnimatorSet的所有当前目标对象。
  • 这里先说一下setDuration,setInterpolator,setTarget这几个方法,当子动画中有设置与animatorSet冲突时,以animatorSet为准
  • 再说一下setStartDelay这个设置延迟的方法,他与子动画设置延迟是不冲突的,也就是可以这样理解,当animatorSet(1000)之后,就相当于你在调用animatorSet.start之后,他内部实际上是1秒之后才去start的,之后的各个子动画的延时就是他们自己的事儿了

总结

  • 到这里,这个set部分就讲完了,基本就是这些东西,具体情况看项目需求,或者还可以去研究官方文档,地址在那面都有贴