Android之动画(Java代码实现)2

Android之动画(Java代码实现)2

文章链接:Android之动画(Java代码实现)2
相关链接: Android之动画(Java代码实现)1

知识点:

概述
  1. ValueAnimator的ofInt()/ofFloat()/ofArgb()构造方法详解和使用;
  2. ObjectAnimator动画类详解和使用;
  3. AnimatorSet类集合类详解和使用;
  4. 自定义速率;
  5. 新名词记录{自定义速率:TimeInterpolator;AnimatorSet:动画的集合控制类;ObjectAnimator:可以定义动作方法的类;Animator:动作基类;}

概述

Animator作为Android四大补间动画基类,我在上一篇文章已经讲了,请戳这里 Android之动画(Java代码实现)1。后来一看,继承此基类的类还有不少,比如ValueAnimator,ObjectAnimator,AnimatorSet等等,他们其实都是来做动画的。

下面将一一来讲解这几个类的效果和用法。


ValueAnimator动画类

前方高能,绑好安全带

前方高能,绑好安全带

前方高能,绑好安全带

先来一个重点分析:ValueAnimator的静态构造函数一共有3个,分别是ofInt(),.ofFloat().ofArgb()三个,如何来理解呢?很简单,三个函数都是传入不限制个参数,拿ofInt()来说,例如我们传入ofInt(0, 400),然后我们设置执行时间setDuration(3000),那么他就是在3000毫秒之内走0–400间隔,步进就是400/3000(距离/时间)。到这里应该可以理解了吧,通俗来讲,就是我们给他一个“距离”,希望这个动画在setDuration(时间)的时间内走完。.ofFloat().ofArgb()同理可得,一个是帮我们走float类型和argb颜色类型。系不系很简单。

那么问题就来了,我们让API帮我们走过这个距离,那这个是要干嘛用啊?

因为是我叫你帮我计算的嘛,所以我希望可以把每走一步的值,都给回我,让我自己去根据这些值进行相应的操作。嗯呢,这是个好的想法。实际上Google也是这样想的。我计算了步进值,并走完,但是我不能帮你实现神马功能啊,只能教会给你咯。所以Google的API提供了一个回调函数ValueAnimator.AnimatorUpdateListener()。只要实现这个函数,然后设置给动画的执行者,那么我就可以将值回传给你了。

那么这个ValueAnimator动画执行者的3个函数大概就是这么回事。现在理解起来系不系很简单了?!

当然,执行者还有其他的属性可以设置,比如是否重复,重复的次数,计算的速率是加速/减速还是其他等等,都是可以调用相应方法进行设置的。

下面一个方法,是获取屏幕的宽度,然后使得要动画的值”在0至屏幕宽度之间进行计算,并且是reverse的。然后我们在回调函数里头进行的设置就是设置图片的左边距,使得“从左到右,再从右到左”进行无限循环滚动。

高能区结束

高能区结束

高能区结束

下面看代码。

void valueAnimationTest() {
        DisplayMetrics metric = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metric);
        int width = metric.widthPixels; // 屏幕宽度(像素)

        /**
         * 意思就是:从0--400,走的都是float类型的数值,步进为((400-0)/3000)pix/ms
         */
        //1.调用ofInt(int...values)方法创建ValueAnimator对象
//        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, width - imgV_animator.getWidth());
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, width - imgV_animator.getWidth());
        valueAnimator.setDuration(3000); //设置动画的时间
        valueAnimator.setInterpolator(new AccelerateInterpolator()); //设置为加速
        //给动画添加更新的监听
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //获取到上面从0--屏幕宽度之间执行的值,步进为400/3000/ms
                float animatorValue = (float) animation.getAnimatedValue();
                //获取到imageview的布局参数
                ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) imgV_animator.getLayoutParams();
                //设置左边距
                marginLayoutParams.leftMargin = (int) animatorValue;
                imgV_animator.setLayoutParams(marginLayoutParams);
            }
        });
        //设置为无限
        valueAnimator.setRepeatCount(INFINITE);
        /**
         * ValueAnimator.RESTART:重头开始执行动画
         * ValueAnimator.REVERSE:执行到尽头之后,反过来执行动画
         * 使用规则,只有当setRepeatCount()为INFINITE和整数值上面两个属性才能起作用
         */
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        valueAnimator.setTarget(imgV_animator); //设置需要动画的view
        valueAnimator.start();
    }

这里的效果图就不上了,暂时不会录GIF,见谅。只有一个静态效果图。


ObjectAnimator动画类

我们有了前面的ValueAnimator类,功能挺强大的了,为什么我们还需要ObjectAnimator类呢?

首先让我们去看看这个类是干嘛的。ObjectAnimator是ValueAnimator的一个子类。其实这个类说白了,就是在ValueAnimator的基础上,添加了set/get方法,这些方法是用来设置我们想要动画的函数的名字的,通过setPropertyName()和getPropertyName()两个对应的方法。

这又要怎么理解呢?我们知道在rotation旋转中,可以设置旋转的中心,例如代码就是下面就是根据自身中点为旋转中心,旋转360度。

<rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" />

那么我们在代码中就可以这样做了

void initView() {
        //根据x轴选中360度
        final ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imgV_animator2, "rotationX", 0, 360);
        objectAnimator.setDuration(2000);
        objectAnimator.setRepeatCount(INFINITE); //无限循环
        objectAnimator.setInterpolator(new BounceInterpolator());
        //添加动画更新时的监听,可以做一些操作
        objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
            }
        });
        objectAnimator.start();
    }

效果是imgV_animator2图片根据x轴,进行360的无限次数翻转。

上面的代码看不懂?没关系,待我慢慢道来。首先我们来看到构造函数

    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {}

参数解析:

参数1:需要动画的view;

参数2:动作的名字;

参数3:float类型的集合;

关于参数2,我们可以这样理解:就是我需要进行那一个动作,比如rotationX,就是view根据x轴进行翻转多少度,翻转的度数由参数3决定。

下面我收集了一些动作的名字,因为比较多,难记,故要写下来,供自己查阅
rotationX:根据x轴翻转

rotationY:根据y轴翻转

scaleX:根据x轴缩放

scaleY:根据y轴缩放

translationX:根据x轴平移

translationY:根据y轴平移

rotation:根据中心店翻转

to be continue

当然,这个类的构造函数比较多,以下的构造方法。

public static ObjectAnimator ofArgb(Object target, String propertyName, int... values) {}

public static <T> ObjectAnimator ofArgb(T target, Property<T, Integer> property, int... values) {}

public static <T> ObjectAnimator ofMultiInt(Object target, String propertyName,TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, T... values) {}

public static ObjectAnimator ofMultiInt(Object target, String propertyName, Path path) {

public static ObjectAnimator ofMultiInt(Object target, String propertyName, int[][] values) {}

public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> xProperty,
            Property<T, Integer> yProperty, Path path) {
...

大家可以去阅读源码,看看都是干嘛用的。我这里就不做一一的解释了。我们还是看看怎么去使用。

关于ObjectAnimator类,上面说了,是可以利用set/get方法设置需要动作的名字的,如下就是将

        final ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imgV_animator2, "rotationX", 0, 10);
        //设置动画的名称为rotationY
        objectAnimator.setPropertyName("rotationY");

AnimatorSet类

AnimatorSet类继承Animator类,也是一个动画类。她的作用是:根据一定的顺序播放一个动画的集合。顺序分别有:一起播放,顺序播放和延时播放。

既然是一个集合,那么我就可以一次设置多几个需要动画的集合,然后按着我的顺序进行动画播放了。

下面是代码:

 @TargetApi(Build.VERSION_CODES.KITKAT)
    void animatorSet() {
        AnimatorSet animatorSet = new AnimatorSet();
        /*
        ObjectAnimator obj1 = ObjectAnimator.ofFloat(imgV_animator, "scaleX", 1.0f,0.5f,1.0f);
        ObjectAnimator obj2 = ObjectAnimator.ofFloat(imgV_animator, "scaleY", 1.0f,0.5f,1.0f);
        ObjectAnimator obj3 = ObjectAnimator.ofFloat(imgV_animator, "rotationX", 0.0f,180.0f,0.0f);
        //playobj1动画之后,跟着obj2动画
        animatorSet.play(obj1).after(obj2);
        animatorSet.play(obj2).after(obj3);
        //设置共同播放
        animatorSet.playTogether(obj1, obj2, obj3);
        //设置播放的循序obj1-》ojb2-》ojb3
        animatorSet.playSequentially(obj1, obj2, obj3);
        animatorSet.start();
        */

        //和上面的一毛一样,只是方法不同而已
        animatorSet.playSequentially(
                //重y轴-100(屏幕外)移动至0的位置
                ObjectAnimator.ofFloat(imgV_animator, "translationY", -100, 0),
                //在从0-1淡出来
                ObjectAnimator.ofFloat(imgV_animator, "alpha", 0, 1));
        animatorSet.setDuration(2000);
        animatorSet.setStartDelay(2000);

        //添加动画停止或者调用停止之后再重新播放动画
        animatorSet.addPauseListener(new Animator.AnimatorPauseListener() {
            @Override
            public void onAnimationPause(Animator animation) {
                //动画停止回调
            }

            @Override
            public void onAnimationResume(Animator animation) {
                //调用停止之后再重新播放动画的回调
            }
        });
        animatorSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                //监听上一个动画结束之后,再进行缩放操作
                AnimatorSet animatorSet2 = new AnimatorSet();
                animatorSet2.playTogether(
                        //从1缩放到0.2在缩放到1的动画集合
                        ObjectAnimator.ofFloat(imgV_animator, "scaleX", 1f, 0.2f, 1f),
                        ObjectAnimator.ofFloat(imgV_animator, "scaleY", 1f, 0.2f, 1f)
                );
                animatorSet2.setInterpolator(new AccelerateInterpolator());
                animatorSet2.setDuration(2000);
                animatorSet2.start();
            }
        });
        animatorSet.start();
    }

*顺序的设定*:一起执行动画的方法playTogether(),有好几个重载方法;
设置顺序播放动画的方法:playSequentially(),也有好几个,基本上都是差不多的。大家可以都去试一试。**

具体的看代码就可以了。再说一句,imgV_animator/imgV_animator2都是imageview来的。


XML里面定义动画

当然,我们也是可以在XML文件里面设置上面几个动画的,在AnimatorSet类的开头就讲了。我们看看具体是怎么来写的。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together">

    <!--android:ordering="sequentially|together"
    sequentially:按顺序
    together:全部一起-->

    <objectAnimator
        android:duration="500"
        android:interpolator="@android:anim/linear_interpolator"
        android:propertyName="scaleX"
        android:valueFrom="1.0"
        android:valueTo="0.5"
        android:valueType="floatType" />

    <objectAnimator
        android:duration="500"
        android:interpolator="@android:anim/linear_interpolator"
        android:propertyName="scaleY"
        android:valueFrom="1.0"
        android:valueTo="0.5"
        android:valueType="floatType" />

    <objectAnimator
        android:duration="500"
        android:interpolator="@android:anim/linear_interpolator"
        android:propertyName="rotationX"
        android:valueFrom="0.0"
        android:valueTo="360.0"
        android:valueType="floatType" />

    <valueAnimator
        android:duration="500"
        android:interpolator="@android:anim/linear_interpolator"
        android:propertyName="rotationX"
        android:valueFrom="0.0"
        android:valueTo="360.0"
        android:valueType="floatType" />
</set>

这里我就不多讲了,你有看过四种动画 Android之动画(Java代码实现)1,那就可以理解XML中每个属性的意义了。


最后关于如何自定义速率

自定义速率,重写类,然后计算返回的因子。但是我还没有认真去研究,权当留白先了。等有时间在去看这里的内容。

public class CustomInterpolator implements TimeInterpolator {  

    @Override  
    public float getInterpolation(float input) {  
        // 编写相关的逻辑计算  
        //input *= 0.8f;  
        return input * input;  
    }  
}  

总结

上面的内容还是不少的,很多估计都没怎么接触过,但是只要多看几遍,你会发现,其实这个动画不难,并且用户巨大啊。想着明天我就可以在实战中使用了。共勉。

最后说一句,为毛在markdown编辑器上面会那么好看,但是来到CSDN上面就没那么好看了呢?!尤其是代码块的查看,颜色浅,很难看清的感觉。当然,好学的你是不会太在意这些问题的。

如有任何问题,请及时与我联系,谢谢!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值