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

2018-04-08  本文已影响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) {  
    }  
}); 

源码

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

上一篇下一篇

猜你喜欢

热点阅读