Android基础夯实--重温动画(五)之属性动画 ObjectAnimator详解
只有一种真正的英雄主义
一、摘要
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实现同样的效果,控件水平方向上的不断左右移动,最后返回原点(如下图)。
通过上一节的学习,我们可以轻松写出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方向上伸缩。
所以对应代码为:
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):设置阴影。
所以对应代码为:
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);
所以对应代码为:
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轴旋转。
所以对应代码为:
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属性值进行改变。
例如颜色值的变化。
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属性值进行改变。
例如实现一个贝塞尔曲线:
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的效果,大家可以对比一下代码:
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 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来加深和进阶使用,这样在我们用到时方能得心应手。
Android基础夯实--重温动画(五)之属性动画 ObjectAnimator详解的更多相关文章
- Android基础夯实--重温动画(四)之属性动画 ValueAnimator详解
宝剑锋从磨砺出,梅花香自苦寒来:千淘万漉虽辛苦,吹尽狂沙始到金: 长风破浪会有时,直挂云帆济沧海 一.摘要 Animator类作为属性动画的基类,它是一个抽象类,它提供了实现动画的基本架构,但是我们不 ...
- Android基础夯实--重温动画(一)之Tween Animation
心灵鸡汤:真正成功的人生,不在于成就的大小,而在于你是否努力地去实现自我,喊出自己的声音,走出属于自己的道路. 摘要 不积跬步,无以至千里:不积小流,无以成江海.学习任何东西我们都离不开扎实的基础知识 ...
- Android基础夯实--重温动画(二)之Frame Animation
心灵鸡汤:天下事有难易乎,为之,则难者亦易矣:不为,则易者亦难矣. 摘要 当你已经掌握了Tween Animation之后,再来看Frame Animation,你就会顿悟,喔,原来Frame Ani ...
- Android基础夯实--重温动画(三)之初识Property Animation
每个人都有一定的理想,这种理想决定着他的努力和判断的方向.就在这个意义上,我从来不把安逸和快乐看作生活目的的本身--这种伦理基础,我叫它猪栏的理想.--爱因斯坦 一.摘要 Property Anima ...
- <Android 基础(二十五)> View Animation
简介 视图动画,主要包括位移,透明度,旋转和缩放,View本身的属性并没有发生变化,只是在这个视图上添加一些渐变的效果,所以总体而言,视图动画只能实现一些简单的动画效果,属性动画功能更强大. 使用 r ...
- Android View 的绘制流程之 Layout 和 Draw 过程详解 (二)
View 的绘制系列文章: Android View 的绘制流程之 Measure 过程详解 (一) Android View 绘制流程之 DecorView 与 ViewRootImpl 在上一篇 ...
- moviepy音视频剪辑:视频剪辑基类VideoClip的属性及方法详解
☞ ░ 前往老猿Python博文目录 ░ 一.概述 在<moviepy音视频剪辑:moviepy中的剪辑基类Clip详解>和<moviepy音视频剪辑:moviepy中的剪辑基类Cl ...
- “全栈2019”Java异常第十五章:异常链详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- css3浏览器私有属性前缀使用详解
什么是浏览器私有属性前缀 CSS3的浏览器私有属性前缀是一个浏览器生产商经常使用的一种方式.它暗示该CSS属性或规则尚未成为W3C标准的一部分. 以下是几种常用前缀 -webkit- -moz- -m ...
随机推荐
- Windows下安装MySQL5.6绿色版
建议安装MySQL绿色版的,什么是绿色版的?就是免安装,下载下来的截图是这样的 在该目录下创建一个文件夹/data用于存放数据, 新建一个my.ini文件,my.ini里面最基本的配置如下,my.in ...
- Elasticsearch - 搜索类型与搜索位置
一.搜索类型: Elasticsearch同意用户选择其所希望的处理查询的方式. 由于存在一些不同的情形,对其使用不同的搜索类型才是合适的.为了控制查询的运行方式,我们能够在请求中使用search_t ...
- swift语言初见
下面是swift得基础语法部分内容 // main.swift // helloSwift // // Created by cyteven on 14-7-23. // Copyright ...
- What are some advantages of using Node.js over a Flask API?
https://www.quora.com/What-are-some-advantages-of-using-Node-js-over-a-Flask-API Flask is a Python w ...
- PP-判断生产订单状态(关闭)
方法一.工单号通过 resb找到对象号 然后找到状态为I0045利用表JEST与TJ02T . 方法二.函数'STATU_CHECK' 检查工单状态为'I0045' 则为已做技术性关闭. READ T ...
- linux网络socket 接口转
linux网络socket 接口 1.socket函数:一个进程必须做的第一件事就是调用socket函数获得一个文件描述符. ------------------------------------- ...
- ”吐槽“qemu的块设备驱动
花点时间来总结一下前阵子的工作. qemu的底层块设备无疑是我所见过的最复杂的模块了,说得好像我很精通很多模块一样(大雾). 它的raw镜像格式文件的驱动的核心代码主要都是在raw-posix.c文件 ...
- 如何在Android studio中同时打开多个工程?
最近学习Android Studio,想同时打开两个Project.但是点击File->Open之后,原有的Project被关闭掉了.怎么在新的窗口中打开Project呢? 解决: 点击Help ...
- Python: PS 图像调整--亮度调整
本文用 Python 实现 PS 图像调整中的亮度调整,具体的算法原理和效果可以参考之前的博客: http://blog.csdn.net/matrix_space/article/details/2 ...
- Gerrit+apache+H2数据库简单安装配置及建库流程
Gerrit 是一个基于 Web 的代码评审和项目管理的工具,面向基于 Git 版本控制系统的项目.因此需要Apache.Mysql.GIT等相关软件的支持 系统配置: 新装的UBANTU LINUX ...