Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用

前言:把握生命里的每一分钟,全力以赴心中的梦。不经历风雨,怎么见彩虹,没有人能随随便便成功。           ----《真心英雄》

一、概述

        我们在上一篇文章中已经详细讲解了ObjectAnimator的使用,但是ValueAnimator和ObjectAnimator只能简单实现一个动画,如果我要实现一个组合动画呢?比如一边缩放,一边移动那怎么办?系统也提供了一个AnimatorSet属性动画组合类,由于ValueAnimator比较少用到,这里就讲解ObjectAnimator配合AnimatorSet的使用。另外,这里最后增加了PropertyValuesHolder用法的讲解。

1、基本属性

AnimatorSet继承自Animator类,Animator类有的属性AnimatorSet都有,这里列出常用的一部分函数:

    /**
     * 开启动画
     */
    void start()
    /**
     * 设置动画时间
     */
    AnimatorSet setDuration(long duration)
    /**
     * 退出动画
     */
    void cancel()
    /**
     * 设置插值器
     */
    void setInterpolator(TimeInterpolator interpolator)

监听器:

/**
 * 监听器一:监听动画变化时四个状态
 */
public static interface AnimatorListener {
    void onAnimationStart(Animator animation);
    void onAnimationEnd(Animator animation);
    void onAnimationCancel(Animator animation);
    void onAnimationRepeat(Animator animation);
}
//添加方法为:public void addListener(AnimatorListener listener) 
 
/**
 *监听器二:监听动画暂停和暂停后再恢复的状态
 */
    public static interface AnimatorPauseListener {
        void onAnimationPause(Animator animation);
        void onAnimationResume(Animator animation);
    }
//添加方法:public void addPauseListener(AnimatorPauseListener listener)

这些属性在《Android动画篇(三)—— 属性动画ValueAnimator的使用》已经作了详细解释,这里就不一一细讲了。

 

二、基本使用

1、示例

    ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff);
        color.setEvaluator(new ArgbEvaluator());
        ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f);
        //构建AnimatorSet实例
        AnimatorSet animatorSet  = new AnimatorSet();
        animatorSet.playTogether(color, translation);
        //添加动画监听
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                Log.e(TAG, "onAnimationStart");
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                Log.e(TAG, "onAnimationEnd");
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                Log.e(TAG, "onAnimationCancel");
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                Log.e(TAG, "onAnimationRepeat");
            }
        });
        //设置动画时长
        animatorSet.setDuration(2000);
        //开启动画
        animatorSet.start();

效果如下:

从图中可以看出,我们设置了两个动画,一个颜色渐变,一个向下移动,调用playTogether()函数后,两个动画都同时启动了。

2、playTogether和playSequentially

(1)playTogether

  • playTogether(Animator... items)                       同时开启动画,参数是可变长参数,参数为需要执行的动画
  • playTogether(Collection<Animator> items)       同时开启动画,参数是动画合集

这里的函数都是一样的,只是参数不一样,第一个传入的是可变长参数,第二个传入的是集合Collection<Animator> items,我们来看看playTogether的用法:

ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff);
        color.setEvaluator(new ArgbEvaluator());
        ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f);
        ObjectAnimator translation2 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0f, 600f, 0f);
        //构建AnimatorSet实例
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(color, translation, translation2);
        //设置动画时长
        animatorSet.setDuration(2000);
        //开启动画
        animatorSet.start();

效果图如下:

从图中可以看出,开启动画的时候,三个动画时同时执行的,tv1的背景颜色变化和位移以及tv2的位移都是同时开始。

(2)playSequentially

  • playSequentially(Animator... items)             逐个播放动画,可变长参数,参数为需要执行的动画
  • playSequentially(List<Animator> items)      逐个播放动画,参数为需要执行的动画的集合

我们来看看使用playSequentially会有怎么样的效果:

ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff);
        color.setEvaluator(new ArgbEvaluator());
        ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f);
        ObjectAnimator translation2 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0f, 600f, 0f);
        //将动画添加到集合中
        List<Animator> animatorList = new ArrayList<>();
        animatorList.add(color);
        animatorList.add(translation);
        animatorList.add(translation2);

        //构建AnimatorSet实例
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playSequentially(animatorList);
        //设置动画时长
        animatorSet.setDuration(2000);
        //开启动画
        animatorSet.start();

效果如下:

从上面的效果可以看到,动画时一个执行完以后再执行下一个动画,动画合集里面我们是一个个添加进去的,即先加入颜色变化动画,再加入tv1的移动,最后加入tv2的移动动画。调用playSequentially()是将动画组装起来然后依次播放动画。

那么,我们如果第一个动画一直在执行没有结束动画呢?即将第一个动画设置为无限循环,那会是怎么样的效果,我们来看看:

ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff);
        color.setEvaluator(new ArgbEvaluator());
        //设置循环模式
        color.setRepeatMode(ValueAnimator.REVERSE);
        //设置无限循环
        color.setRepeatCount(ValueAnimator.INFINITE);

        ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f);
        ObjectAnimator translation2 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0f, 600f, 0f);
        //将动画添加到集合中
        List<Animator> animatorList = new ArrayList<>();
        animatorList.add(color);
        animatorList.add(translation);
        animatorList.add(translation2);

        //构建AnimatorSet实例
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playSequentially(animatorList);

        //设置动画时长
        animatorSet.setDuration(2000);
        //开启动画
        animatorSet.start();

效果:

从上面看到,三个动画已经通过playSequentially添加,第一个动画设置了无限循环,开始后永远不会结束,那么下一个动画也就无法开始。

3、AnimatorSet.Builder函数

上面我们知道playTogether和playSequentially能同时开始动画和逐个开始动画,但是如果我想再一个动画开始后,同是开始另外两个动画怎么?系统还提供了一个AnimatorSet.Builder类,这个类是由mAnimatorSet.play(Animator anim)产生的,并且是唯一能产生这个类的方法。我们来看看AnimatorSet.Builder的使用:

(1)常用函数

    /**
     * 表示要播放那个动画
     * 获取AnimatorSet.Builder对象的唯一方法
     */
    public AnimatorSet.Builder play(Animator anim)
    /**
     * 表示和前面的动画一起执行
     */
    public AnimatorSet.Builder with(Animator anim)
    /**
     * 表示anim动画在执行Builder动画之后执行(Builder动画在anim动画之前)
     */
    public AnimatorSet.Builder before(Animator anim)
    /**
     * 表示anim动画在执行Builder动画之前执行(Builder动画在anim动画之后)
     */
    public AnimatorSet.Builder after(Animator anim)
    /**
     * 表示在延迟多少时间后执行该动画,单位为毫秒
     */
    public AnimatorSet.Builder after(long delay)

(2)示例

我们使用上面的方法做一个例子:

ObjectAnimator color1 = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff);
        color1.setEvaluator(new ArgbEvaluator());
        ObjectAnimator translation1 = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f);
        ObjectAnimator translation2 = ObjectAnimator.ofFloat(mTextView2, "translationY", 0f, 600f, 0f);
        ObjectAnimator rotation2 = ObjectAnimator.ofFloat(mTextView2, "rotation", 0f, 360f, 0f);

        //构建AnimatorSet实例
        AnimatorSet animatorSet = new AnimatorSet();
        //获取builder实例
        AnimatorSet.Builder builder = animatorSet.play(color1);//builder播放动画color1
        builder.with(translation1);//跟随builder一起播放translation1
        builder.before(translation2);//builder在动画translation2之前播放
        builder.after(rotation2);//builder在动画rotation2之后播放

        //链式写法
        //builder.with(translation1).before(translation2).after(rotation2);

        //设置动画时长
        animatorSet.setDuration(2000);
        //开启动画
        animatorSet.start();

效果如下:

从效果图可以看出,tv2先旋转after(rotation2),然后tv1背景色变化并且向下移动play(color1),with(translation1);最后才执行tv2向下移动before(translation2);

所以以play(color1)中的动画为基准,with(translation1)会跟随play()中的动画一起执行,after(rotation2)是在play()动画之前执行,也就是说rotation2最先执行,before(translation2)在play()之后执行。也可以这样理解:play()动画在after(rotation2)之后执行,play()动画在before(translation2)之前执行,其实就是以谁来定基准而已,谁在谁前后执行,这里比较容易混淆。

我们也可以将这部分的代码简化为链式写法:

builder.with(translation1).before(translation2).after(rotation2);

4、AnimatorSet监听器

我们为AnimatorSet添加监听器,通过addListener(AnimatorListener listener)添加:

ObjectAnimator color = ObjectAnimator.ofArgb(mTextView1, "backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff);
        color.setEvaluator(new ArgbEvaluator());
        color.setRepeatCount(ValueAnimator.INFINITE);
        color.setRepeatMode(ValueAnimator.REVERSE);
        ObjectAnimator translation = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f);
        //构建AnimatorSet实例
        AnimatorSet animatorSet  = new AnimatorSet();
        animatorSet.playTogether(color, translation);
        //添加动画监听
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                Log.e(TAG, "onAnimationStart");
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                Log.e(TAG, "onAnimationEnd");
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                Log.e(TAG, "onAnimationCancel");
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                Log.e(TAG, "onAnimationRepeat");
            }
        });
        //设置动画时长
        animatorSet.setDuration(2000);
        //开启动画
        animatorSet.start();

注意:监听器必须在start()启动动画之前设置,否则有可能接受不到onAnimationStart(Animator animation)等函数的监听。

点击start anim按钮启动动画,一段时间后点击cancel anim按钮结束动画,效果如下:

从上面的代码中,我们设置了TextView1向下移动一次,背景颜色无限循环改变,点击start anim按钮,tv1启动动画,向下移动后回到原点,背景色做无限循环变色,然后我们点击cancel anim 按钮,打印出来的log如上图,只是打印了开始,退出,结束动画,并没有打印onAnimationRepeat()函数,得出结论:

(1)AnimatorSet设置的监听函数也是仅仅监听AnimatorSet的状态,与动画无关。

(2)AnimatorSet中没有设置循环次数的方法,所以AnimatorSet设置的监听方法永远运行不到onAnimationRepeat()中。

5、其他函数单个设置的区别

   /**
     * 设置动画目标控件
     */
    void setTarget(Object target)()
    /**
     * 设置动画时间
     */
    AnimatorSet setDuration(long duration)
    /**
     * 设置插值器
     */
    void setInterpolator(TimeInterpolator interpolator)

其中AnimatorSet与单个控件拥有函数由一部分是相同的,如果同时使用他们会不会冲突呢?我们来校验一下他们的使用区别:

 ObjectAnimator translation1 = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f);
        translation1.setDuration(5000);
        translation1.setInterpolator(new BounceInterpolator());
        ObjectAnimator rotation2 = ObjectAnimator.ofFloat(mTextView2, "rotation", 0f, 360f, 0f);
        rotation2.setDuration(10000);
        rotation2.setInterpolator(new AccelerateInterpolator());
        
        //构建AnimatorSet实例
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(translation1).with(rotation2);

        //设置动画时长
        animatorSet.setDuration(1000);
        animatorSet.setTarget(mTextView1);
        animatorSet.setInterpolator(new LinearInterpolator());
        //开启动画
        animatorSet.start();

从上面的代码中,我们设置了mTextView1在5秒完成动画,向下移动400后再回到原点,插值器为BounceInterpolator;mTextView2在10秒内完成动画,旋转360度,再回到0度,插值器为AccelerateInterpolator。动画集合animatorSet设置了1秒,目标控件为mTextView1,插值器为LinearInterpolator,效果如下:

从动画中可以看出,只有mTextView1做了动画,一秒内向下移动并且旋转然后回到原点,那么说明AnimatorSet中设置的会覆盖单个动画中设置的函数,我们再来看看AnimatorSet没有设置的时候是什么效果:

 ObjectAnimator translation1 = ObjectAnimator.ofFloat(mTextView1, "translationY", 0f, 400f, 0f);
        translation1.setDuration(5000);
        translation1.setInterpolator(new BounceInterpolator());
        ObjectAnimator rotation2 = ObjectAnimator.ofFloat(mTextView2, "rotation", 0f, 360f, 0f);
        rotation2.setDuration(10000);
        rotation2.setInterpolator(new AccelerateInterpolator());

        //构建AnimatorSet实例
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(translation1).with(rotation2);
        //开启动画
        animatorSet.start();

效果如下:

可以看出AnimatorSet没有设置的话则以单个动画中设置的为准。得出结论:

AnimatorSet设置以后会覆盖单个动画的设置,单个动画的设置变为无效;如果AnimatorSet没有设置则以单个动画的设置为准。

三、高级用法(PropertyValuesHolder的使用)

ValueAnimator和ObjectAnimator除了通过ofInt()、ofFloat()、ofObject()还可以通过PropertyValuesHolder来创建实例,由于ValueAnimator用的比较少,这里使用ObjectAnimator来配合PropertyValuesHolder使用,来看看PropertyValuesHolder的构造方法:

//ValueAnimator
ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
//ObjectAnimator 
ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)
  • Object target                                      指定执行动画的控件
  • PropertyValuesHolder... values         可变长参数,可以传入多个PropertyValuesHolder实例,每一个实例都会针对控件做动                                                                    画,多个实例会对控件同时做多个动画

PropertyValuesHolder的意义就是保存动画过程中所需要的属性和值,其实ofInt()和ofFloat()的内部实现就是通过封装PropertyValuesHolder实例来保存动画状态的,后面的操作也是以PropertyValuesHolder为主。

我们来看看创建PropertyValuesHolder实例的函数:

public static PropertyValuesHolder ofInt(String propertyName, int... values)
public static PropertyValuesHolder ofFloat(String propertyName, float... values)
  • propertyName                 需要操作的属性名,通过反射需要找到的属性方法名
  • values                             属性所对应的参数,可变长参数

有不理解的同学可以参考《Android动画篇(五)—— 属性动画ObjectAnimator基本使用

 //创建PropertyValuesHolder实例
        PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofInt("backgroundColor", 0xffff00ff, 0xffffff00, 0xff0000ff);
        valuesHolder1.setEvaluator(new ArgbEvaluator());
        PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("scaleX", 0f, 2f, 0f, 3f, 1f);
        PropertyValuesHolder valuesHolder3 = PropertyValuesHolder.ofFloat("scaleY", 0f, 2f, 0f, 3f, 1f);
        //将创建PropertyValuesHolder实例添加到ObjectAnimator中
        ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mTextView1, valuesHolder1, valuesHolder2, valuesHolder3);
        objectAnimator.setDuration(2000);
        objectAnimator.start();

创建PropertyValuesHolder实例后,将实例分别添加到ObjectAnimator中,执行动画

效果如下:

好了,有关动画集合的就这里结束了,有需要的朋友可以回头看看我前面写的几篇动画文章!

源码下载地址:https://github.com/FollowExcellence/AndroidAnimation

请大家尊重原创者版权,转载请标明出处: https://blog.csdn.net/m0_37796683/article/details/90645047 谢谢!

动画系列文章:

1、 Android动画篇(一)—— alpha、scale、translate、rotate、set的xml属性及用法

  • 补间动画的XML用法以及属性详解

2、Android动画篇(二)—— 代码实现alpha、scale、translate、rotate、set及插值器动画

  • 代码动态实现补间动画以及属性详解

3、 Android动画篇(三)—— 属性动画ValueAnimator的使用

  • ValueAnimator的基本使用

4、 Android动画篇(四)—— 属性动画ValueAnimator的高级进阶

  • 插值器(Interpolator)、计算器(Evaluator)、ValueAnimator的ofObject用法等相关知识

5、 Android动画篇(五)—— 属性动画ObjectAnimator基本使用

  • ObjectAnomator的基本使用以及属性详解

6、 Android动画篇(六)—— 组合动画AnimatorSet和PropertyValuesHolder的使用

  • AnimatorSet动画集合和PropertyValuesHolder的使用

以上几篇动画文章是一定要掌握的,写的不好请多多指出!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ViewPager是一个Android中的View容器,可以让用户在多个页面之间进行滑动切换。要实现多页面滑动切换以及动画效果,可以按照以下步骤: 1. 在XML布局文件中添加ViewPager控件,并添加对应的布局文件,例如: ``` <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 2. 在Java代码中为ViewPager设置Adapter,用于显示多个页面。例如: ``` ViewPager viewPager = findViewById(R.id.viewPager); MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager()); viewPager.setAdapter(adapter); ``` 其中,MyPagerAdapter是自定义的PagerAdapter类,需要继承自FragmentPagerAdapter或FragmentStatePagerAdapter。 3. 在自定义的PagerAdapter类中实现getItem()方法,用于返回每个页面的Fragment实例。例如: ``` @Override public Fragment getItem(int position) { switch (position) { case 0: return new Fragment1(); case 1: return new Fragment2(); case 2: return new Fragment3(); default: return null; } } ``` 其中,Fragment1、Fragment2、Fragment3是自定义的Fragment类,用于显示对应页面的内容。 4. 如果需要添加页面切换的动画效果,可以在Java代码中为ViewPager设置PageTransformer。例如: ``` viewPager.setPageTransformer(true, new DepthPageTransformer()); ``` 其中,DepthPageTransformer是自定义的PageTransformer类,用于实现页面切换时的动画效果。可以参考以下代码示例: ``` public class DepthPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0f); } else if (position <= 0) { // [-1,0] // Use the default slide transition when moving to the left page view.setAlpha(1f); view.setTranslationX(0f); view.setScaleX(1f); view.setScaleY(1f); } else if (position <= 1) { // (0,1] // Fade the page out. view.setAlpha(1 - position); // Counteract the default slide transition view.setTranslationX(pageWidth * -position); // Scale the page down (between MIN_SCALE and 1) float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0f); } } } ``` 以上就是实现Android中ViewPager多页面滑动切换以及动画效果的步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值