您现在的位置是:首页 > 文章详情

Android 基础动画之属性动画详解

日期:2018-08-19点击:342

在上两篇文章主要介绍了 Android 基础动画之帧动画 以及 Android 基础动画之补间动画 。本篇文章主要介绍的是Android基础动画之 属性动画

补间动画 这篇文章的末尾有说道,补间动画执行完毕以后,加载的view实际上是没有点击事件的,因为点击事件依旧附着在原来的view位置,所以这种动画的完整体验有点蜜汁尴尬。为了解决这种设计之初带来的体验问题,Android3.0以后开始引入属性动画来完美解决这一历史遗留问题。

属性动画的强大之处在于,它可以作用到任何对象(不仅仅针对视图View对象),另外,属性动画还可以自定义各种动画效果(不仅仅是平移、旋转、缩放、透明度的变化)。那么属性动画是如何做到这些功能的?它的原理是在一定时间内,不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果。

说完了属性动画的作用和优点,下面就用代码去学习掌握属性动画。其中属性动画有两个非常重要的类:分别是ValueAnimator 类、ObjectAnimator 类。

ObjectAnimator:

ObjectAnimator简单理解是直接对对象的属性值进行改变操作,从而实现动画效果。ObjectAnimator本质是通过不断控制值的变化,再不断自动赋给对象的属性,从而实现动画效果。ObjectAnimator一般推荐是代码进行使用(下面是基本代码和一些常见的API):

 //目标view TextView mTextView = findViewById(R.id.ob_text); //平移动画 ObjectAnimator translationAnimator = ObjectAnimator.ofFloat(mTextView, "translationX", 200); // 设置动画运行的时长 translationAnimator.setDuration(500); // 设置动画延迟播放时间 translationAnimator.setStartDelay(500); // 设置动画重复播放次数 = 重放次数+1 // 动画播放次数 = infinite时,动画无限重复 translationAnimator.setRepeatCount(0); // 设置重复播放动画模式 // ValueAnimator.RESTART(默认):正序重放 // ValueAnimator.REVERSE:倒序回放 translationAnimator.setRepeatMode(ValueAnimator.RESTART); //开始动画 translationAnimator.start(); //旋转动画 ObjectAnimator rotation = ObjectAnimator.ofFloat(mTextView,"rotation",90); rotation.setDuration(500); rotation.start(); //缩放动画 ObjectAnimator scaleX = ObjectAnimator.ofFloat(mTextView,"scaleX",1.5f); scaleX.setDuration(500); scaleX.start(); //透明度动画 ObjectAnimator alpha = ObjectAnimator.ofFloat(mTextView,"alpha",0.2f); alpha.setDuration(500); alpha.start(); 

你可能会问,那我想通过ObjectAnimator来同时实现多个效果一起运行,那该怎么办?
如果想通过一个ObjectAnimator同时改变多个属性,则需要使用PropertyValuesHolder,参考代码如下:

 PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("translationX",200); PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("translationY",200) ; PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("rotation",90) ; PropertyValuesHolder holder4 = PropertyValuesHolder.ofFloat("scaleX",1.5f) ; PropertyValuesHolder holder5 = PropertyValuesHolder.ofFloat("alpha",0.2f) ; //ObjectAnimator.ofPropertyValuesHolder() //参数一:目标view //参数二:可变参数 支持多个PropertyValuesHolder ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mTextView, holder1, holder2,holder3,holder4,holder5); animator.setDuration(500); animator.start(); 

下面在来看看ValueAnimator

ValueAnimator

ValueAnimator实现动画的原理是通过不断控制值的变化,然后手动赋给对象的属性,从而实现动画效果。ValueAnimator的大致流程是,先指定将初始值以何种数值(整型、浮点型)的形式 过渡到结束值;接着,开发者手动将值,赋值给目标的属性值。接下来的步伐涉及到了别的内容(插值器与估值器)但还是会慢慢分析。

ValueAnimator重要的方法我基于面向对象的设计原则将其分为两类三个(本质是一类),当然这是我自己的理解。既然是面向对象的设计语言,那么第一步肯定是 new 对象,那么ValueAnimator这个类 new 对象的第一种姿势是这样的:

 /** * ValueAnimator创建对象姿势一: * 调用ofInt(int...)、ofFloat(float...) * 形参是可变参数、可传多个参数 * 将传入的多个Int参数进行平滑过渡:假设此处传入0和3,表示将值从0平滑过渡到3 * 以此类推如果传入了3个Int参数 a,b,c ,则是先从a平滑过渡到b,再从b平滑过渡到C, */ ValueAnimator animInt = ValueAnimator.ofInt(0, 3); ValueAnimator animFoat = ValueAnimator.ofFloat(0, 3); 

既然拿到了ValueAnimator实例对象以后,接下来就调用对象提供的方法实现具体的功能( 下面是参考代码 )

 textView = findViewById(R.id.ob_text); ValueAnimator animInt = ValueAnimator.ofInt(0, 3); // 设置动画运行的时长 animInt.setDuration(500); // 设置动画延迟播放时间 animInt.setStartDelay(500); // 设置动画重复播放次数 = 重放次数+1 // 动画播放次数 = infinite时,动画无限重复 animInt.setRepeatCount(0); // 设置重复播放动画模式 // ValueAnimator.RESTART(默认):正序重放 // ValueAnimator.REVERSE:倒序回放 animInt.setRepeatMode(ValueAnimator.RESTART); animInt.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float fraction = animation.getAnimatedFraction(); float value = (float) animation.getAnimatedValue(); Log.i("app","属性值:"+"fraction:"+fraction+",value:"+value); //在这里设置具体的动画属性值 textView.setTranslationX(value); } }); //开启动画 animInt.start(); 

说完了第一种new ValueAnimator对象的姿势,现在说第二种:

 /** * ValueAnimator实例化对象姿势二: * 参数一:TypeEvaluator 估值器 * 参数二:Object... values 可变参数,可以传入具体的动画对象(开始-结束) */ ValueAnimator valueAnimator = ValueAnimator.ofObject(new TypeEvaluator() { @Override public Object evaluate(float fraction, Object startValue, Object endValue) { return null; } },"",""); 

可以看到,通过ofObject这个函数实例化ValueAnimator对象的时候,需要我们传入一个TypeEvaluator,
以及一个可变参数Object,下面就这2个参数着重说明:

参数一:TypeEvaluator(估值器)

这个就是我们经常提到的估值器。估值器和插值器是很多开发容易搞混淆的一个概念,面试的时候也会问到这个(因为自定义控件会附加动画的内容)本着不抛弃不放弃的精神、下面就对这两个概念进行详尽分析:

首先,这个TypeEvaluator(估值器)本质是一个接口,源码如下:

 public interface TypeEvaluator<T> { /** * This function returns the result of linearly interpolating the start and end values,with * <code>fraction</code> representing the proportion between the start and end values. The * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>, * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, * and <code>t</code> is <code>fraction</code>. * * @param fraction The fraction from the starting to the ending values * @param startValue The start value. * @param endValue The end value. * @return A linear interpolation between the start and end values, given the * <code>fraction</code> parameter. */ public T evaluate(float fraction, T startValue, T endValue); } 

其实,通过源码的英文注释就可以分析出这个估值器的实际作用(英文注释翻译过来就是):这个函数返回线性插值起始值和结束值的结果。其中参数fraction代表起始值和结束值之间的比例。简单的计算公式是:result = x0 + t * (x1 - x0);参数的具体是指:x0=startValue;x1=endValue;t=fraction最后,这个方法返回的是,在开始和结束值之间的线性插值,给定分数参数。

简单点说就是,估值器是通过计算公式来进行的值的计算。

还有一点,之前说的ValueAnimator.ofFloat()以及ValueAnimator.ofInt(),这2个方法内部实际上由系统已经设置好了对应的估值器,分别是FloatEvaluator以及IntEvaluator,所以虽然是“两类三个”,但本质上来说还是属于"一类"。

另外既然我们知道了计算公式、那么就可以根据业务定制自己的估值器,下面是参考拓展代码:

 /** * TypeEvaluator里面的泛型可以根据业务去订制 */ class MyEvaluator implements TypeEvaluator<Object>{ @Override public Object evaluate(float fraction, Object startValue, Object endValue) { /** * 计算公式自己随意拓展 */ return null; } } 

接着将这个自定义的估值器设置到我们的ValueAnimator即可:

 ValueAnimator valueAnimator = ValueAnimator.ofObject(new MyEvaluator()); 

说完了TypeEvaluator我们在来看看插值器:Interpolator:

Interpolator(插值器)

依旧打开源码目睹下庐山真面目:

/** * An interpolator defines the rate of change of an animation. This allows * the basic animation effects (alpha, scale, translate, rotate) to be * accelerated, decelerated, repeated, etc. */ public interface Interpolator extends TimeInterpolator { // A new interface, TimeInterpolator, was introduced for the new android.animation // package. This older Interpolator interface extends TimeInterpolator so that users of // the new Animator-based animations can use either the old Interpolator implementations or // new classes that implement TimeInterpolator directly. } 

嗯,英文注释非常详细,首先是类注释,翻译过来如下:差值器定义了动画的变化速率。这允许基本的动画(透明、缩放、平移、旋转)效果可以加速,减速,重复,等等。关于接口方法内的注释主要是关于新旧版本TimeInterpolator的一些说明。

另外,笔者的Android SDK系统版本是26,所以源码可能会有一些不同。

透过英文注释可以得知:插值器的功能主要是为了丰富(透明、缩放、平移、旋转)这些动画的效果。比如,我们可以通过插值器去设置炫丽的效果,让以往的动画生冷平稳的过渡效果成为历史,让动画变的更立体、更有灵魂。也就是让动画效果变化的模式更客观

系统也为我们提供了一些默认的插值器方便我们使用:


img_b3680ec4de435941c338fafc5808610e.png
插值器

那么,如何使用系统为我们提供好的插值器?声明一个插值器有两种写法:

  • 写法一:通过xml文件,对标签的内容进行编写

首先: res/animator的文件夹路径内里创建相应的动画xml

接着:代码编写

<animator xmlns:android="http://schemas.android.com/apk/res/android" // 初始值 android:valueFrom="0" // 结束值 android:valueTo="100" // 变化值类型 :floatType & intType android:valueType="intType" // 动画持续时间(ms),必须设置,动画才有效果 android:duration="3000" // 动画延迟开始时间(ms) android:startOffset ="1000" // 动画播放完后,视图是否会停留在动画开始的状态,默认为true android:fillBefore = “true” // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false android:fillAfter = “false” // 是否应用fillBefore值,对fillAfter值无影响,默认为true android:fillEnabled= “true” // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart| android:repeatMode= “restart” // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复 android:repeatCount = “0” // 插值器 这里等价于OvershootInterpolator android:interpolator = "@android:anim/overshoot_interpolator" /> 

其中,这里的 android:interpolator 标签代表的就是Java中的OvershootInterpolator这个系统为我们写好的插值器

  • 写法二:Java代码编写
 ValueAnimator valueAnimator = ValueAnimator.ofObject(new MyEvaluator()); Animation animation = new AlphaAnimation(1,0); //调用setInterpolator 使用插值器 animation.setInterpolator(new OvershootInterpolator()); 

那系统自带的插值器代表的意思是什么?

Interpolator 资源ID 功能
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 先加速再减速
AccelerateInterpolator @android:anim/accelerate_interpolator 加速
AnticipateInterpolator @android:anim/anticipate_interpolator 先后退一小步然后加速前进
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 先后退一小步再加速前进,超出终点一小步再回到终点
BounceInterpolator @android:anim/bounce_interpolator 最后阶段弹球效果
CycleInterpolator @android:anim/cycle_interpolator 周期运行
DecelerateInterpolator @android:anim/decelerate_interpolator 减速
LinearInterpolator @android:anim/linear_interpolator 匀速
OvershootInterpolator @android:anim/overshoot_interpolator 快速到达终点并超出一小步然后回到终点

嗯,以上九个插值器所带来的各种效果是很丰富的(比如,最后一个阶段有弹球的效果;或者先加速再减速),很多博客和资料也是说的是九个。如果你细心看完上面那张系统父子关系层级截图,你会发现系统明明为我们生成了10个默认的插值器,但是你这里只有9个?难道是写漏了一个?嗯,多余的一个是PathInterpolator

打开PathInterpolator源码可以看到它的两个构造函数,生成的path其实是一个贝赛尔曲线。有兴趣的小伙伴可以自行查阅资料去了解该插值器的使用和说明。

回到正题,一般来说,系统为我们提供的插值器基本上就可以满足开发需求了,如果还是不能满足我们就可以自定义插值器:

 class MyInterpolator implements Interpolator{ @Override public float getInterpolation(float input) { /** * 在这里做自己想要做的逻辑 */ return 0; } } 

关于自定义插值器里面的getInterpolation(float input)这个方法需要说明一下,这里的input的取值范围是0 - 1,另外,在这个方法内部我们就可以根据业务进行自己想要的计算。

总结:

属性动画是Android3.0之后出现的动画,不仅解决了之前的历史遗留问题,而且通过搭配估值器与插值器的效果让我们的动画更加立体形象、丰富多彩。

如果这篇文章对你有帮助,希望各位看官留下宝贵的star,谢谢。

Ps:著作权归作者所有,转载请注明作者, 商业转载请联系作者获得授权,非商业转载请注明出处(开头或结尾请添加转载出处,添加原文url地址),文章请勿滥用,也希望大家尊重笔者的劳动成果

原文链接:https://yq.aliyun.com/articles/657482
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章