文档章节

Android基础夯实--重温动画(五)之属性动画 ObjectAnimator详解

Ryane
 Ryane
发布于 2017/03/28 11:39
字数 3333
阅读 73
收藏 0

只有一种真正的英雄主义

欢迎大家想看更多关于Android基础夯实系列博文,请移步到我的博客: Ryane's Blog

一、摘要

ObjectAnimator是ValueAnimator的子类,它和ValueAnimator一样,同样具有计算属性值的功能,但对比ValueAnimator,它会更加容易使用,因为它不再需要设置监听器来监听值的变化,因为这个工程对于ObjectAnimator来说,是自动的。这篇文章主要通过详细讲解ObejctAniamtior,加深大家对属性动画的认识,让我们对于动画的技巧掌握得更扎实。

如果你想了解更权威的解释,可以查看官方文档:Property Animation

本文主要对ValueAnimator做介绍,如果大家有兴趣,可以继续阅读本动画系列其他相关文章,作者也在不断更新完善相关内容,希望大家可以指出有误之处。

Android基础夯实--重温动画(一)之Tween Animation

Android基础夯实--重温动画(二)之Frame Animation

Android基础夯实--重温动画(三)之初识Property Animation

Android基础夯实--重温动画(四)之属性动画 ValueAnimator详解

二、 概述

在上节我们知道了在属性动画中,ValueAnimator是通过监听值的变化,然后实现控件的动画播放。在代码过程中,是通过设置初始值、结束值和动画时间,然后通过加速器返回当前的进度的,再经过Evaluator根据进度计算出具体的值,然后我们在监听器里面不断监听拿到这个值,然后修改控件的属性值,从而实现动画。

ObjectAnimator作为ValueAnimator的子类,所以ValueAnimator的很多方法,在ObjectAnimator中也能使用,但是ObjectAnimator覆写了父类的几个方法,如ofInt(),ofFloat(),ofArgb()等。它和ValueAnimator同样也是首先设置初始值、结束值和动画时长,但是同时也绑定了目标控件和属性然后通过加速器返回当前的进度的,再经过Evaluator根据进度计算出具体的值,最后根据属性拼接set函数并反射调用,并将当前值作为参数传入,实现动画。

对比这两个Animator,ObjectAnimator是对ValueAnimator的再封装,它的封装帮助我们避免了使用Listener的麻烦,更加精简了代码,使开发者可以更加专注动画的逻辑代码。

2.1 差异

以下通过Demo来对比ObjectAnimator和ValueAnimator的区别,我们同样使用ObjectAnimator和ValueAnimator实现同样的效果,控件水平方向上的不断左右移动,最后返回原点(如下图)。

Demo

通过上一节的学习,我们可以轻松写出ValueAnimator实现的代码:

ValueAnimator animator = ValueAnimator.ofFloat(0, 300, -100, 200, -50, 0);
animator.setDuration(2000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        mBinding.image.setTranslationX((Float) animation.getAnimatedValue());
    }
});

在ObjectAnimator中,我们可以用更简单的代码来实现:

ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "translationX", 0, 300, -100, 200, -50, 0);
animator.setDuration(2000);
animator.start();

通过对比,我们可以看到,ObjectAnimator在实现动画上的代码上会更加简洁,但是实现的效果都是一样的,之所以是这样,是因为ObjectAnimator覆写了ValueAnimator 的ofFloat方法,并对其进行了封装。所以,我们看到ObjectAnimator实现代码上都减少了Listener代码的编写。

大家第一次看到ObjectAnimator可能看到代码比较陌生,上面的一段代码什么意思呢?首先我们看到第一个参数,就是我们动画的目标控件,也就是这个动画要让哪个控件来实现,我这里是DATABinding的一个写法,其实就是我们findViewById得到的一个view,非常的简单;第二个参数是动画要实现的效果,我这里是translationX,即水平x方向上的位移;第三个参数为可变参数,即动画变化过程的系列值,跟ValueAnimator是一样的意思。

参数

2.2 propertyName

在2.1的介绍过后,大家可能还会有疑问,对于上面ofFloat的第二个参数是一个字符串常量,这个字符串常量我们是怎么获取的呢?其实,在ObejctAnimator中,无论ofFloat,ofInt,ofArgb等方法,都有一个叫做propertyName的参数,也就是我们上面对应的第二个参数,这个参数是一个字符串,之所以动画会实现该字符串的效果是因为ObjectAnimator通过反射机制,找到了ImageView中的setTranslationX()这个方法,然后每个十几ms就调用这个方法,并把我们的变化的值传到里面去,从而实现动画效果。

所以到这里大家可以知道,当我们需要用ObjectAnimator实现一个控件的动画效果时,我们首先需要做的就是在这个控件中找到对应的setXXX()驼峰式写法的方法,只有控件拥有相应的setXXX()方法, 我们传入的propertyName参数才起到作用。那么这时候就有同学会问,类似Demo中的“translationX”,它对应的方法是setTranslationX(),那我们应该传入“TranslationX”还是“translationX”,其实都是可以的,因为它内部封装在使用反射机制调用方法时,涵盖了两种写法,所以第一个字母可以大小写,但是后面的字母必须全部对应大小写。

其次还要同学会疑问,我们怎么知道在实例化ObjectAnimator时应该通过ofFloat还是ofInt还是其他呢?其实跟我们的ValueAnimator一样,我们调用哪个方法来实例化都是要考虑我们要改变的控件哪个属性的。例如,我们上面的例子是改变水平方向上的位移,那么ObjectAnimator最终是调用控件的setTranslationX(float translationX),我们可以看到传入参数是float型,那么毫无疑问,我们这里需要使用ofFloat了,其它以此类推。下面给大家举例一些常用的propertyName。

2.2.1 Scale

View中关于伸缩变化(Scale)有以下两个方法:

  • public void setScaleX(float scaleX):X方向上伸缩。
  • public void setScaleY(float scaleY):Y方向上伸缩。

Scale

所以对应代码为:

ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "scaleX", 0f, 1.5f, 2f, 1.5f, 0f, 0.5f, 0.2f, 1f);
mBinding.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
animator.setDuration(2000);
animator.start();
View view = new View(MyObjectAnimator.this);
ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "scaleY", 0f, 1.5f, 2f, 1.5f, 0f, 0.5f, 0.2f, 1f);
animator.setDuration(2000);
mBinding.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
animator.start();

2.2.2 Translation

View中关于位置变化(Translation)有以下两个方法:

  • public void setTranslationX(float translationX):X轴上位移。
  • public void setTranslationY(float translationY):Y轴上位移。
  • public void setTranslationZ(float translationZ):设置阴影。

Translation

所以对应代码为:

ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "translationX", 0, 100, -100, 0);
mBinding.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
animator.setDuration(2000);
animator.start();
ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "translationY", 0, 100, -100, 0);
animator.setDuration(2000);
mBinding.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
animator.start();

2.2.3 Alpha

View中关于透明度变化(Alpha)有以下方法:

  • public void setAlpha(float alpha);

Alpha

所以对应代码为:

ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "alpha", 0, 0.5f, 1.0f);
mBinding.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
animator.setDuration(2000);
animator.start();

2.2.4 Rotation

View中关于角度变化(Rotation)有以下方法:

  • public void setRotation(float rotation):关于Z轴旋转。
  • public void setRotationX(float rotationX):关于X轴旋转。
  • public void setRotationY(float rotationY):关于Y轴旋转。

Rotation

所以对应代码为:

ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "rotation", 0, 180, 0, -180, 0);
mBinding.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
animator.setDuration(3000);
animator.start();
ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "rotationX", 0, 180, 0, -180, 0);
animator.setDuration(3000);
mBinding.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
animator.start();
ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "rotationY", 0, 180, 0, -180, 0);
animator.setDuration(3000);
mBinding.image.setScaleType(ImageView.ScaleType.CENTER_CROP);
animator.start();

2.2.5 图片变化

View中关于图片的其中一个方法是setBackgroundResource,同样我们也可以通过ObjectAnimator来实现一个图片变化的效果:

  • public void setBackgroundResource(@DrawableRes int resid)

图片变化

对应代码为:

ObjectAnimator animator = ObjectAnimator.ofInt(mBinding.image, "backgroundResource", R.drawable.a1, R.drawable.a2, R.drawable.a3);
animator.setDuration(2000);
animator.start();

其实还有很多set方法可以可以实现动画效果,这里就不再一一列举,大家有兴趣可以自己去深入研究,你会发现ObjectAnimator可以非常简单快捷地实现动画效果。

2.3 实例化ObjectAnimator方法

在ValueAnimator中,我们知道实例化并不是通过new一个对象出来,而是通过ofInt,ofFloat,ofObject等方法。在ObjectAnimator中同样如此,因为ofInt,ofFloat,ofObject等方法的内部帮我们封装了实例化过程,所以我们可以直接调用来拿到一个实例化的对象。在ObjectAnimator中,大概有以下几种实例化方法:

2.3.1 ofInt()

通过ofInt()来实例化对象,那么属性值必须为int型,通常我们通过ofInt可以实现很多动画,例如实现颜色渐变等;ofInt()也有几个重载函数,这里介绍其中一个:

  • ofInt(Object target, String propertyName, int... values):对目标对象T的property属性值进行改变。

例如颜色值的变化。

ofInt

ObjectAnimator animator = ObjectAnimator.ofInt(mBinding.image, "backgroundColor",  0xffff00ff, 0xffffff00, 0xffff00ff);
animator.setEvaluator(new ArgbEvaluator());
animator.setDuration(4000);
animator.start();

2.3.2 ofFloat()

ofFloat()来实例化对象,那么属性值必须为float型,通常我们通过ofFloat可以实现很多动画,例如实现位置变化等;ofFloat()也有几个重载函数,这里介绍其中一个:

  • ObjectAnimator ofFloat (Object target, String xPropertyName, String yPropertyName, Path path)::对目标对象T的property属性值进行改变。

例如实现一个贝塞尔曲线:

ofFloat

Path path = new Path();
path.quadTo(800, 200, 800, 800);
ObjectAnimator animator = ObjectAnimator.ofFloat(mBinding.image, "x", "y", path);
animator.setDuration(4000);
animator.start();

2.3.3 ofArgb()

我们在ValueAnimator中已经提到了ofArgb()可以帮助我们实现颜色的渐变效果,这里同样是可以通过ofArgb()来实现动画效果。上面我们已经在ofInt里面实现了颜色渐变,但是代码稍多,所以Google在API LEVEL 21之后增加了这个方法ofArgb()。通过这个方法我们更容易地实现颜色演变,因为它里面封装了对ArgbEvaluator的使用,实现2.3.1的效果,大家可以对比一下代码:

ofInt

ObjectAnimator animator = ObjectAnimator.ofArgb(mBinding.image, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
animator.setDuration(4000);
animator.start();

2.3.4 ofPropertyValuesHolder()

认真的同学都会发现,在ValueAnimator和ObjectAnimator中,都有一个实例化方法,就是ofPropertyValuesHolder()方法,由于在ObjectAnimator中使用更为广泛,所以这里以ObjectAnimator的ofPropertyValuesHolder为例子,当大家懂了之后,那么大家对ValueAnimator的ofPropertyValuesHolder也应该理解了。

在ObjectAnimator中,我们可以通过

  • ObjectAnimator ofPropertyValuesHolder (Object target, PropertyValuesHolder... values)

来实例化一个ObjectAnimator。

我们可以看到,它和我们其他的实例化方法差不多,都需要设置一个target(目标控件),还有一组PropertyValuesHolder类型的值,但是不需要设置属性,target我们知道了,是要实现动画的控件,那么PropertyValuesHolder是什么呢?我们来看一下官方文档:

This class holds information about a property and the values that that property should take on during an animation. PropertyValuesHolder objects can be used to create animations with ValueAnimator or ObjectAnimator that operate on several different properties in parallel.

什么意思呢?

这是一个包含一个属性信息的类,并且它的值应该用到一个动画里面。PropertyValuesHolder对象可以配合ValueAnimator和ObjectAnimator来实现不同属性的并行的动画。

听起来有点别扭,也就是说,当我们需要实现一个包含多种属性的同时播放的动画时,我们就可以使用ofPropertyValuesHolder来实例化一个Animator,当然,拥有一个属性时也是可以的,为什么这么说?ofFloat()的内部实现其实就是将传进来的参数封装成PropertyValuesHolder实例来保存动画状态。所以可见PropertyValuesHolder是多么有用了吧。

在PropertyValuesHolder这个类里面,同样也有ofInt(),ofFloat(),ofKeyframe()等方法来实例化,举个例子:

PropertyValuesHolder

代码也非常简单:

PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("Rotation", 90, -90, 45, -45, 60, -60);
PropertyValuesHolder colorHolder = PropertyValuesHolder.ofInt("BackgroundColor", 0xff55aa11, 0xff115633, 0xff123344, 0xffaabbcc);
PropertyValuesHolder scaleXHolder = PropertyValuesHolder.ofFloat("ScaleX", 1f, 1.1f, 1.2f, 1.5f, 1.8f, 1.5f, 1.2f, 1.1f, 1);
PropertyValuesHolder scaleYHolder = PropertyValuesHolder.ofFloat("ScaleY", 1f, 1.1f, 1.2f, 1.5f, 1.8f, 1.5f, 1.2f, 1.1f, 1);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mBinding.image, rotationHolder, colorHolder, scaleXHolder, scaleYHolder);
animator.setDuration(3500);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();

通过代码我们可以知道,通过ofPropertyValuesHolder来实例化,其实就是将不同动画效果分配到一个个PropertyValuesHolder中去,然后把多个不同的PropertyValuesHolder对象在初始化时传入,最终实现多个效果并行播放。

2.3.4 其他实例化方法

在ObjectAnimator中提供了非常丰富的实例化方法,除了以上三个之外,在API LEVEL 21之后,Google推出了更多的实例化方法,例如:

  • ofMultiFloat()
  • ofMultiInt()
  • ofObject()
  • ofPropertyValuesHolder()

在上面三个(2.3.1-2.3.3)不足以解决我们需求的时候,我们可以到官方文档参考这三个比较新的实例化方法,它们也是为了简化操作而进行了更高度的封装,所以这也有助于帮助我们用更少的代码来实现动画。

总结

ObjectAnimator作为ValueAnimator的子类,在代码上对ValueAnimator进行了进一步的封装,使我们在日常使用中更加简单,但是正是因为封装,使得我们在一些特殊情况下使用ObjectAnimator使用上还是有一定的局限性,所以在大家掌握了ValueAnimator和ObjectAnimator的基本使用后,还需要自己通过写小Demo来加深和进阶使用,这样在我们用到时方能得心应手。

© 著作权归作者所有

Ryane
粉丝 42
博文 22
码字总数 55318
作品 0
程序员
私信 提问
Android属性动画---Property Animation(八)

用ViewPropertyAnimator制作动画 ViewPropertyAnimator类使用一个单一的Animator对象,给一个View对象的几个动画属性平行处理提供一种简单的方法。它的行为非常像ObjectAnimator类,因为它修...

长平狐
2012/10/16
470
0
Android应用资源---动画资源(Animation Resources)

有两种类型的动画资源: 属性动画 在设定的时间内,通过修改与Animator类相关的对象的属性值来创建一个动画。 视图动画 有两种类型的视图动画框架 补间动画(Tween animation):通过执行通过...

davidpark
2014/02/01
1K
0
Android应用资源---动画资源(Animation Resources)(一)

有两种类型的动画资源: 属性动画 在设定的时间内,通过修改与Animator类相关的对象的属性值来创建一个动画。 视图动画 有两种类型的视图动画框架 补间动画(Tween animation):通过执行通过...

长平狐
2012/10/16
266
0
Android View动画开发笔记

1. android动画分为view动画、帧动画和属性动画,属性动画是API 11(Android 3.0)的新特性,帧动画一般也认为是view动画 1.1 view动画 平移动画 TranslateAnimation 缩放动画 ScaleAnimation...

燊在锦官城_
2016/07/21
0
0
Android开发之漫漫长途 XVII——动画(续)

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ...

马飞标
2018/08/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

rime设置为默认简体

转载 https://github.com/ModerRAS/ModerRAS.github.io/blob/master/_posts/2018-11-07-rime%E8%AE%BE%E7%BD%AE%E4%B8%BA%E9%BB%98%E8%AE%A4%E7%AE%80%E4%BD%93.md 写在开始 我的Arch Linux上......

zhenruyan
今天
5
0
简述TCP的流量控制与拥塞控制

1. TCP流量控制 流量控制就是让发送方的发送速率不要太快,要让接收方来的及接收。 原理是通过确认报文中窗口字段来控制发送方的发送速率,发送方的发送窗口大小不能超过接收方给出窗口大小。...

鏡花水月
今天
10
0
OSChina 周日乱弹 —— 别问,问就是没空

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @tom_tdhzz :#今日歌曲推荐# 分享容祖儿/彭羚的单曲《心淡》: 《心淡》- 容祖儿/彭羚 手机党少年们想听歌,请使劲儿戳(这里) @wqp0010 :周...

小小编辑
今天
1K
11
golang微服务框架go-micro 入门笔记2.1 micro工具之micro api

micro api micro 功能非常强大,本文将详细阐述micro api 命令行的功能 重要的事情说3次 本文全部代码https://idea.techidea8.com/open/idea.shtml?id=6 本文全部代码https://idea.techidea8....

非正式解决方案
今天
5
0
Spring Context 你真的懂了吗

今天介绍一下大家常见的一个单词 context 应该怎么去理解,正确的理解它有助于我们学习 spring 以及计算机系统中的其他知识。 1. context 是什么 我们经常在编程中见到 context 这个单词,当...

Java知其所以然
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部