美文网首页
Android 之Animator属性动画讲解【上】

Android 之Animator属性动画讲解【上】

作者: 々志尚 | 来源:发表于2018-04-08 15:57 被阅读0次

    android Animator 讲解【上】

    目录

    1.简介
    2.属性动画相对补间动画和帧动画好处
    3.ValueAnimator 属性动画
    4.ObjectAnimator 属性动画
    5.AnimatorSet组合动画
    6.使用XML编写动画
    7.动画监听器

    简介

    使用安卓手机的朋友的都知道,手机上面有一些效果比较炫酷。因为系统在一开始的时候就给我们提供了两种实现动画效果的方式:
      逐帧动画(frame-by-frame animation)
      补间动画(tweened animation)

    逐帧动画的理解比较简单,其实就是把一个完整的动画拆分成一张张图片,然后再把他们串联起来进行播放,有点像看视频一样

    补间动画是可以进行对View进行一系列的动画操作,包括淡入淡出、缩放、平移、旋转4种效果。

    在Android3.0之后官方给出一种全新的动画模式,属性动画(property animation),它的功能非常强大,弥补了之前补间动画的一些缺陷,几乎是可以完全替代掉补间动画了。

    属性动画相对补间动画和帧动画好处

    Android之前推存的补间动画是相对于View来就行操作的,比如说对view进行移动、缩放、旋转、淡入淡出等常见效果。但是如果我们的需求超出這写操作,那么补间动画就不能满足我们了。补间动画的扩展性能是有相当大的局限性的,既然补间动画不能胜任需求。那么我们就该换另一种更有满足我们扩展性能更好的动画了。

    属性动画

    为什么属性动画能胜任我们的需求呢?
    相对补间动画的效果,比如我对這个view 就行点击事件监听,原位置是(10,10),但是我在该为进行了补间动画的移动一个位置(100,100),当我们去点事该vew的时候,事件不会被触发,点击原来的位置(10,10)事件被触发了。
    为什么会這样?
    因为补间动画只是改变了view的显示效果,但是并没有改变该view位置状态,view控件依然在位置(10,10)中。

    Android3.0推存出来的属性动画,不仅能够实现补间动画的效果,还能填补补间动画的不足。属性动画是相对于属性来改变View的,所以上面的移动到(100,100)位置,view的 X和Y属性自然也是100了,所以当你点击该vewi的时候,事件在位置(100,100)触发了,在位置(10,10)没有被触发!

    ValueAnimator 属性动画

    ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。

    还有ValueAnimator的用法却一点都不复杂,我们先从最简单的功能看起吧,比如说想要将一个值从0平滑过渡到1,时长100毫秒,就可以这样写:

    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
    anim.setDuration(100);
    anim.start();

    很简单的代码就可以构建出一个属性动画实例。设置的动画是100我们来看一下ofFloat源码

    public static ValueAnimator ofFloat(float... values) {ValueAnimator anim =new ValueAnimator();    anim.setFloatValues(values);    return anim;}

    可以看出,這里的ofFloat方法里面可以传入很多个float,是以数组的形式的一个参数。如下代码:

    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
    anim.setDuration(300);
    // 监听变化状态
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) {
    // 打印 log animation.getAnimatedValue()  
     }});
    setAnimatorListener(anim, "没有添加控件状态下测试ofInt");

    anim.start();

    如图所示:

    从打印的值中,我们可以看出数值是从0到1变大的,而且增加不是均匀的。当然我们也可以设置均匀的增加,不过這个知识点刘下一章在讲解。

    在ValueAnimator中,我们还可以调用setStartDelay()方法来设置动画延迟播放的时间,调用setRepeatCount()和setRepeatMode()方法来设置动画循环播放的次数以及循环播放的模式,循环模式包括RESTART和REVERSE两种,分别表示重新播放和倒序播放的意思。需要连接的可以百度一下,因为这已经是很成熟的技术了。

    ObjectAnimator属性动画

    ObjectAnimator 是 ValueAnimator的子类,也是我们在开发中接触最多的一个类。既然是ValueAnimator的子类,那么ValueAnimator可以用的方法ObjectAnimator 当然也可以用了,ObjectAnimator 也是很好用的。比如想把一个TextView做淡入淡出的效果,效果是這样子的:不透明 》全透明》不透明》半透明》透明》不透明

    ObjectAnimator anim = ObjectAnimator
                .ofFloat(textView, "alpha", 1f, 0f, 1f, 0.5f, 0f, 1f);
    anim.setDuration(3000);
    anim.start();

    效果如下:

    第一个参数是 给定的控件 View ,第二个参数可能很多人不理解,其实這个参数是可以随意起的,就是你可以随意传任何对象,他所负责的工作就是不断的向你起的這个属性对象进行赋值,然后根据属性值的改变在如何展示出来的。

    就拿刚刚的這个来说

    ObjectAnimator.ofFloat(textView, "alpha", 1f, 0f, 1f, 0.5f, 0f, 1f);

    textView是没有存在這个 alpha 属性的,它的父类View也是一样没有這个 alpha 属性。是不是奇怪,很有属性怎么又变成了是属性对象?别急,慢慢跟大家分析,其实這个 alpha 属性不是根据View中有没有這个属性的,而是根据 view中是否存在 alpha 的set和get方法的,我们设置的动画也是一样哦,设置 alpha 就是为了去 view中寻找 alpha对应的 setAlpha 和 getAlpha 方法。不信的同学可以在 View中进行查询哦。

    第三个参数就不用多说了吧 ,上面有提到他是一个数组形式的参数,可以传多个对应的类型执行动画效果。

    根据上面的第二个参数是可以在View中获取set、get方法的,那么如果第二个参数是:rotation、translationX、translationY、scaleX、scaleY也是一样可以在View中找到他们的set和get方法的。说了那么多,为什么這个参数是這样子的,可以自己命名吗? 答案是肯定的,這个参数也可以自定义自己的一个属性名字,上面提到过,而刚刚说的那些 alpha、rotation、translationX、translationY、scaleX、scaleY 都是系统View中自带的set、get方法,也是一样没有這个属性名,只有对应的方法名。

    如果我们要想自己定义属性,下一章我们在重点学习。

    AnimatorSet组合动画

    什么是组合动画呢?

    组合动画就是能实现将多个动画组合到一起播放!

    实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:

        after(Animator anim)   将现有动画插入到传入的动画之后执行
        after(long delay)   将现有动画延迟指定毫秒后执行
        before(Animator anim)   将现有动画插入到传入的动画之前执行
        with(Animator anim)   将现有动画和传入的动画同时执行

    看一下几个方法实现的效果:

    ObjectAnimator anim1 = ObjectAnimator
            .ofFloat(mTest, "translationX", 0f, 400f, -50f, 270f, -150f, 100f, 0f);

    ObjectAnimator anim2 = ObjectAnimator
            .ofFloat(mTest, "translationY", 0f, 400f, -50f, 270f, -150f, 100f, 0f);

    ObjectAnimator anim3 = ObjectAnimator
            .ofFloat(mTest, "rotation", 0f, 360f, -180f, 270f, 0f);

    ObjectAnimator anim4 = ObjectAnimator
             .ofFloat(mTest, "scaleX", 1f, 3f, 2f, 1f);

    AnimatorSet animSet =new AnimatorSet();
    animSet.play(anim1).with(anim2).after(anim3).before(anim4);
    animSet.setDuration(5000);
    animSet.start();

    动画执行顺序:anim3 》anim2+anim1》anim4

    组合动画1

    ObjectAnimator anim1 = ObjectAnimator
              .ofFloat(mTest, "translationX", 0f, 400f, -50f, 270f, -150f, 100f, 0f);

    ObjectAnimator anim2 = ObjectAnimator
             .ofFloat(mTest, "translationY", 0f, 400f, -50f, 270f, -150f, 100f, 0f);

    ObjectAnimator anim3 = ObjectAnimator
             .ofFloat(mTest, "rotation", 0f, 360f, -180f, 270f, 0f);

    AnimatorSet animSet =new AnimatorSet();
    animSet.play(anim1).with(anim2).with(anim3);
    animSet.setDuration(5000);
    animSet.start();

    动画执行顺序:anim1+anim2+anim3 同时执行

    组合动画2


    使用XML编写动画

    除了代码编写动画,其实我们也可以在XML中编写动画。首先我们需要在res中新建一个文件夹 animator 来存储我们编写的动画。

    在XML中,我们有三种标签是可以用来编写动画的:

      < animator > 对应代码中的ValueAnimator

     < objectAnimator > 对应代码中的ObjectAnimator

      < set > 对应代码中的AnimatorSet

    好了,我们来实现一个从0到300平滑过渡的动画,在XML当中就可以这样写:

    <animator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:valueFrom="0"  
    android:valueTo="300"  
    android:valueType="intType" />

    想将一个视图的alpha属性2秒内从1变成0,就可以这样写:

    <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:duration="2000"  
    android:valueFrom="1"  
    android:valueTo="0"  
    android:valueType="floatType"  
    android:propertyName="alpha" />

    用 set 标签组合上面的动画就可以這样子写:

    < set xmlns:android="http://schemas.android.com/apk/res/android"
     android:ordering="sequentially" >  

    < objectAnimator  
         android:duration="2000"  
         android:propertyName="alpha"  
         android:valueFrom="1"  
         android:valueTo="0"  
         android:valueType="floatType"  / >  

    < objectAnimator  
         android:duration="2000"  
         android:valueFrom="0"  
         android:valueTo="300"  
         android:propertyName="translationX "
         android:valueType="intType" / >  

    </set>

    动画监听器

    动画监听器是可以随时随地的监听当前动画执行变化状态的。监听器的功能:监听动画开始前,动画结束,动画当前执行的状态都可以获取。Animator类当中就是提供了一个addListener()方法来实现這写效果的,这个方法接收一个AnimatorListener,我们只需要去实现这个AnimatorListener就可以监听动画的各种事件了。

    该监听器实现AnimatorListener接口有四个方法:

    anim.addListener(new AnimatorListener() {  

    @Override  
    public void onAnimationStart(Animator animation) {  
        }  
    @Override  
    public void onAnimationRepeat(Animator animation) {  
        }  
    @Override  
    public void onAnimationEnd(Animator animation) {  
        }  
    @Override  
    public void onAnimationCancel(Animator animation) {  
        }  
    });  

    onAnimationStart:动画开始的时候调用
    onAnimationRepeat()方法会在动画重复执行的时候调用
    onAnimationEnd()方法会在动画结束的时候调用
    onAnimationCancel()方法会在动画被取消的时候调用。

    有时候我们没有必要实现那么事件方法,只需要四个方法中的某一个,這时候Android提供了一个适配器类,叫作AnimatorListenerAdapter,使用这个类就可以解决掉实现接口繁琐的问题了,如下所示:

    anim.addListener(new AnimatorListenerAdapter() {  
    }); 

    这里我们向addListener()方法中传入这个适配器对象,由于AnimatorListenerAdapter中已经将每个接口都实现好了,所以这里不用实现任何一个方法也不会报错。那么如果我想监听动画结束这个事件,就只需要单独重写这一个方法就可以了,如下所示:

    anim.addListener(new AnimatorListenerAdapter() {  
    @Override  
    public void onAnimationEnd(Animator animation) {  
        }  
    }); 

    源码

    好了,本篇就在此完结了,下篇文章我们重点解析属性动画的类型和插值器

    相关文章

      网友评论

          本文标题:Android 之Animator属性动画讲解【上】

          本文链接:https://www.haomeiwen.com/subject/kdfvcftx.html