属性动画是API 11新加入的特性,和View动画不同,它对作用对象进行了扩展,属性动画可以对任何对象做动画,甚至还可以没有对象。除了作用对象进行了扩展以外,属性动画的效果也得到了加强,不再像View动画那样只能支持四种简单的变换。属性动画中有ValueAnimator、ObjectAnimator和AnimatorSet等概念,通过它们可以实现绚丽的动画。
属性动画可以对任意对象的属性进行动画而不仅仅是View,动画默认时间间隔300ms,默认帧率10ms/帧。其可以达到的效果是:在一个时间间隔内完成对象从一个属性值到另一个属性值的改变。因此,属性动画几乎是无所不能的,只要对象有这个属性,它都能实现动画效果。比较常用的几个动画类是:ValueAnimator
、ObjectAnimator
和AnimatorSet
,其中ObjectAnimator
继承自ValueAnimator
, AnimatorSet
是动画集合,可以定义一组动画,它们使用起来也是极其简单的。
ValueAnimator
ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。
private fun valueAnimator1() {
val anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f)
anim.duration = 5000
anim.addUpdateListener {
val currentValue = it.animatedValue as Float
btnValueAnimator.text = currentValue.toString()
}
anim.startDelay = 1000
anim.start()
}
ObjectAnimator
相对于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator则就不同了,他是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。
不过虽说ObjectAnimator会更加常用一些,但是它其实是继承于ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator仍然是整个属性动画中最核心的一个类。那么既然是继承关系,说明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它们的用法也非常类似,这里如果我们想要将一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
可以看到,我们还是调用了ofFloat()方法来去创建一个ObjectAnimator的实例,只不过ofFloat()方法当中接收的参数有点变化了。这里第一个参数要求传入一个object对象,我们想要对哪个对象进行动画操作就传入什么,这里我传入了一个textview。第二个参数是想要对该对象的哪个属性进行动画操作,由于我们想要改变TextView的不透明度,因此这里传入"alpha"。后面的参数就是不固定长度了,想要完成什么样的动画就传入什么值,这里传入的值就表示将TextView从常规变换成全透明,再从全透明变换成常规。之后调用setDuration()方法来设置动画的时长,然后调用start()方法启动动画。
其它的用法我们就可以举一反三了,那比如说我们想要将TextView进行一次360度的旋转,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
animator.setDuration(5000);
animator.start();
那么如果想要将TextView先向左移出屏幕,然后再移动回来,就可以这样写:
float curTranslationX = textview.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);
animator.setDuration(5000);
animator.start();
然后我们还可以TextView进行缩放操作,比如说将TextView在垂直方向上放大3倍再还原,就可以这样写:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f);
animator.setDuration(5000);
animator.start();
到目前为止,ObjectAnimator的用法还算是相当简单吧,但是我相信肯定会有不少朋友现在心里都有同样一个疑问,就是ofFloat()方法的第二个参数到底可以传哪些值呢?目前我们使用过了alpha、rotation、translationX和scaleY这几个值,分别可以完成淡入淡出、旋转、水平移动、垂直缩放这几种动画,那么还有哪些值是可以使用的呢?其实这个问题的答案非常玄乎,就是我们可以传入任意的值到ofFloat()方法的第二个参数当中。任意的值?相信这很出乎大家的意料吧,但事实就是如此。因为ObjectAnimator在设计的时候就没有针对于View来进行设计,而是针对于任意对象的,它所负责的工作就是不断地向某个对象中的某个属性进行赋值,然后对象根据属性值的改变再来决定如何展现出来。
AnimatorSet
独立的动画能够实现的视觉效果毕竟是相当有限的,因此将多个动画组合到一起播放就显得尤为重要。幸运的是,Android团队在设计属性动画的时候也充分考虑到了组合动画的功能,因此提供了一套非常丰富的API来让我们将多个动画组合到一起。
实现组合动画功能主要需要借助AnimatorSet这个类,常用方法提供了一个playTogether()方法。
private fun animatorSet() {
val set = AnimatorSet()
set.playTogether(
ObjectAnimator.ofFloat(btnObjectAnimator, "alpha", 1f, 0f, 1f),
ObjectAnimator.ofFloat(btnObjectAnimator, "rotation", 0f, 360f),
ObjectAnimator.ofFloat(btnObjectAnimator, "translationX", 0f, -360f, 360f),
ObjectAnimator.ofFloat(btnObjectAnimator, "scaleY", 1f, 3f, 1f)
)
set.setDuration(5000).start()
}
这个类也提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:
- after(Animator anim) 将现有动画插入到传入的动画之后执行
- after(long delay) 将现有动画延迟指定毫秒后执行
- before(Animator anim) 将现有动画插入到传入的动画之前执行
- with(Animator anim) 将现有动画和传入的动画同时执行
好了,有了这四个方法,我们就可以完成组合动画的逻辑了,那么比如说我们想要让TextView先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出操作,就可以这样写:
ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();
可以看到,这里我们先是把三个动画的对象全部创建出来,然后new出一个AnimatorSet对象之后将这三个动画对象进行播放排序,让旋转和淡入淡出动画同时进行,并把它们插入到了平移动画的后面,最后是设置动画时长以及启动动画。
Animator监听器
在很多时候,我们希望可以监听到动画的各种事件,比如动画何时开始,何时结束,然后在开始或者结束的时候去执行一些逻辑处理。这个功能是完全可以实现的,Animator类当中提供了一个addListener()方法,这个方法接收一个AnimatorListener,我们只需要去实现这个AnimatorListener就可以监听动画的各种事件了。
大家已经知道,ObjectAnimator是继承自ValueAnimator的,而ValueAnimator又是继承自Animator的,因此不管是ValueAnimator还是ObjectAnimator都是可以使用addListener()这个方法的。另外AnimatorSet也是继承自Animator的,因此addListener()这个方法算是个通用的方法。
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) {
// 在动画被取消的时候调用
}
});
但是也许很多时候我们并不想要监听那么多个事件,可能我只想要监听动画结束这一个事件,那么每次都要将四个接口全部实现一遍就显得非常繁琐。没关系,为此Android提供了一个适配器类,叫作AnimatorListenerAdapter,使用这个类就可以解决掉实现接口繁琐的问题了,如下所示:
anim.addListener(new AnimatorListenerAdapter() {
});
网友评论