属性动画不仅仅能作用于View,而能作用于任何对象。
ViewAnimation只支持几种动画:scale、transition、rotate、alpha四种类型。并且缺陷是只是改变了显示位置,实际位置并没有改变。 一个demo解释一切,如下图:
Hello按钮使用ViewAnimation进行移动,点击事件在移动后,但是响应还在最初的位置;而属性动画移动的World按钮则不同,响应是跟着按钮走的。
创建一个属性动画,一般需要设置几个参数,如下:
以官方图为例:
一个动画,40ms,从左向右移动40pixel,每隔10ms,新的帧被画出来了,动画停止时,View停在了最终位置。 上面的例子是一个线性的效果,时间插值器的函数是:
pixel=1*time
下面是一个非线性的例子,如图:
这个只需要改变插值器即可,可以看到先加速到一半,再开始减速。 下面开始正式说明属性动画的原理,首先看下图:
可以看到核心是ValueAnimator这个类会追踪动画的时长,当前属性值。 ValueAnimator封装了TimeInterpolation和TypeEvaluator,TimeInterpolation用来计算每一帧对应时间的属性,TypeEvaluator用来从动画中获取属性值。 创建一个动画并开启后,属性动画主要有三步操作:
每一帧,经过这么计算,就是属性动画的原理。
主要是ValueAnimator,ObjectAnimator,AnimatorSet,类结构图如下所示:
Animator和Animation一样,既可以代码实现,也可以在xml中定义,下面分别说明两种方式分别是如何操作的。
ValueAnimator有一些静态方法,ofInt、ofFloat、ofObject。 先看效果,
<?xml version="1.0" encoding="utf-8"?> <animator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="3000" android:interpolator="@android:anim/accelerate_interpolator" android:valueFrom="0" android:valueTo="1000" android:valueType="floatType" />
配合代码:
val animatorFromXml = AnimatorInflater.loadAnimator(this, R.animator.value_move_view) btnMoveFromXml.setOnClickListener { if (animatorFromXml is ValueAnimator) { animatorFromXml.apply { addUpdateListener { tvShow.translationX = it.animatedValue as Float } start() } } }
val animator = ValueAnimator.ofFloat(0f, 1000f) .apply { duration = 3000 interpolator = AccelerateInterpolator() addUpdateListener { tvShow.translationX = it.animatedValue as Float } } btnMove.setOnClickListener { animator.start() }
上面两种实现是一样的效果,耗时3s,transitionX从0变为1000,ValueAnimator需要添加UpdateListener得到实际的属性值,然后赋值给对应View。
效果与上面相同,如下:
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="3000" android:interpolator="@android:anim/accelerate_interpolator" android:propertyName="transitionX" android:valueFrom="0" android:valueTo="1000" android:valueType="floatType" />
配合代码:
val animatorFromXml = AnimatorInflater.loadAnimator(this, R.animator.object_move_view) btnMoveFromXml.setOnClickListener { if(animatorFromXml is ValueAnimator){ animatorFromXml.apply { addUpdateListener { tvShow.translationX=animatedValue as Float } start() } } }
val animator = ObjectAnimator.ofFloat(tvShow,View.TRANSLATION_X,0f,1000f).apply { duration=3000 interpolator=AccelerateInterpolator() } btnMove.setOnClickListener { animator.start() }
与ValueAnimator相比,ObjectAnimator传入了要运动的View,所以也就不需要在UpdateListener中控制View。
如果需要同时开启多个动画,那么可以使用AnimatorSet,串联组织多个动画。 先看效果:
具体效果是首先透明度变化,然后transitionX和transitionY一起变化,最后透明度再变化一波。代码如下:
val alphaStartAnim = ObjectAnimator.ofFloat(tvShow, View.ALPHA, 1f, 0f, 1f) val xAnim = ObjectAnimator.ofFloat(tvShow, View.TRANSLATION_X, 0f, 1000f) val yAnim = ObjectAnimator.ofFloat(tvShow, View.TRANSLATION_Y, 0f, 500f) val alphaEndAnim = ObjectAnimator.ofFloat(tvShow, View.ALPHA, 1f, 0f, 1f) btnMove.setOnClickListener { AnimatorSet().apply { play(xAnim).after(alphaStartAnim) play(xAnim).with(yAnim) play(xAnim).before(alphaEndAnim) start() } }
至此,我们可以使用ValueAnimator、ObjectAnimator或AnimatorSet进行创建动画,然后作用于View或其他对象。
关于代码,参考https://github.com/wangli135/ClimbDemo/tree/master/jetpackdemo/src/main/java/com/xingfeng/jetpackdemo/animation/propertyanimator
本文分享自微信公众号 - 每天学点Android知识(android_every_day),作者:星风coder
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2019-02-19
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句