Android 之Animator属性动画讲解【上】
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
组合动画1ObjectAnimator 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) {
}
});
好了,本篇就在此完结了,下篇文章我们重点解析属性动画的类型和插值器