概述
简介
- 实现属性动画中的一个核心方法类
- 继承自ValueAnimator类,即底层的动画实现机制是基于ValueAnimator类
原理
直接对对象的属性值进行改变操作,从而实现动画效果。如直接改变 View
的 alpha
属性 从而实现透明度的动画效果。
通过不断控制 值 的变化,再不断 自动 赋给对象的属性,从而实现动画效果。如下图:
基础使用
因为是继承了ValueAnimator
类,所以使用的方法和前面学的十分类似:XML
设置 / Java
设置
Java代码设置
1 | ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float ....values); |
上述代码中,如果输入了不存在的 property 属性,Androidstudio会提示的
基本属性
1 | //1、透明度:alpha |
各种属性的详细解释和演示:
https://wiki.jikexueyuan.com/project/android-animation/7.html
XML 代码中设置
res/animator/set_animation.xml
1 | // ObjectAnimator 采用<animator> 标签 |
在Java代码中启动动画
1 | Animator animator = AnimatorInflater.loadAnimator(context, R.animator.set_animation); |
使用实例
1 | public class Demo_ObjectAnimator extends AppCompatActivity { |
效果:
通过自定义对象属性实现动画效果
说明
- 在上面的学习中,我们使用了属性动画最基本的四种动画效果:透明度、平移、旋转 & 缩放
即在
ObjectAnimator.ofFloat()
的第二个参数String property
传入alpha
、rotation
、translationX
和scaleY
等
其实,
ofFloat()
的第二个参数可以传入 任意属性值。ObjectAnimator
类 对 对象属性值 进行改变从而实现动画效果的本质是:通过不断控制 值 的变化,再不断 自动 赋给对象的属性,从而实现动画效果。而 自动赋给对象的属性 的本质是调用该对象属性的 set() & get() 方法进行赋值
所以,
ObjectAnimator.ofFloat(Object object, String property, float ....values)
的第二个参数传入值的作用是:让ObjectAnimator
类根据传入的属性名 去寻找 该对象对应属性名的set() & get()
方法,从而进行对象属性值的赋值,如上面的例子:1
2
3
4
5
6
7
8
9
10
11
12
13ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "rotation", 0f, 360f);
// 其实Button对象中并没有rotation这个属性值
// ObjectAnimator并不是直接对我们传入的属性名进行操作
// 而是根据传入的属性值"rotation" 去寻找对象对应属性名对应的get和set方法,从而通过set() & get()对属性进行赋值
// 因为Button对象中有rotation属性所对应的get & set方法
// 所以传入的rotation属性是有效的
// 所以才能对rotation这个属性进行操作赋值
public void setRotation(float value);
public float getRotation();
// 实际上,这两个方法是由View对象提供的,所以任何继承自View的对象都具备这个属性
原理解析
1 | // 使用方法 |
自动赋值的逻辑:
- 初始化时,如果属性的初始值没有提供,则调用属性的
get()
进行取值; - 当 值 变化时,用对象该属性的
set()
方法,从而从而将新的属性值设置给对象属性。
所以:
ObjectAnimator
类针对的是任意对象 & 任意属性值,并不是单单针对于View对象- 如果需要采用
ObjectAnimator
类实现动画效果,那么需要操作的对象就必须有该属性的set() & get()
具体使用
对于属性动画,其拓展性在于:不局限于系统限定的动画,可以自定义动画,即自定义对象的属性,并通过操作自定义的属性从而实现动画。
那么,该如何自定义属性呢?本质上,就是:
- 为对象设置需要操作属性的
set() & get()
方法 - 通过实现TypeEvaluator类从而定义属性变化的逻辑
- 类似于ValueAnimator的过程
实例练习
实现的动画效果:一个圆的颜色渐变
逻辑如下:
步骤1:设置对象类属性的 set() & get() 方法
通过继承原始类,直接给类加上该属性的
get()
&set()
,从而实现给对象加上该属性的get()
&set()
通过包装原始动画对象,间接给对象加上该属性的
get()
&
set()
。即 用一个类来包装原始对象
下面用第一种来实现一下:
MyView2.java
1 | public class MyView2 extends View { |
步骤2:在布局中引入myview2
1 |
|
步骤3:根据需求实现TypeEvaluator接口
1 | public class ColorEvaluator implements TypeEvaluator { |
步骤4: 调用ObjectAnimator.ofObject() 方法
自定义对象属性,我们用的是 ObjectAnimator.ofObject() 方法,该方法不同于前面的ofFloat(),需要额外传入一个自定义的属性估值器
源码:
1 | public static ObjectAnimator ofObject(Object target, String propertyName, |
方法调用:
1 | public class Demo_ObjectAnimator2 extends AppCompatActivity { |
效果
说明
ObjectAnimator
类 自动赋给对象的属性 的本质是调用该对象属性的set() & get()
方法进行赋值所以,
ObjectAnimator.ofFloat(Object object, String property, float ....values)
的第二个参数传入值的作用是:让ObjectAnimator
类根据传入的属性名 去寻找 该对象对应属性名的set() & get()
方法,从而进行对象属性值的赋值从上面的原理可知,如果想让对象的属性a的动画生效,属性a需要同时满足下面两个条件:
- 1.对象必须要提供属性a的set()方法
a. 如果没传递初始值,那么需要提供 get() 方法,因为系统要去拿属性a的初始值
b. 若该条件不满足,程序直接Crash- 对象提供的 属性a 的
set()
方法 对 属性a的改变 必须通过某种方法反映出来
a. 如带来ui上的变化
b. 若这条不满足,动画无效,但不会Crash
上述条件,一般第二条都会满足,主要是在第一条
- 比如说:由于
View
的setWidth()
并不是设置View
的宽度,而是设置View
的最大宽度和最小宽度的;所以通过setWidth()
无法改变控件的宽度;所以对View
视图的width
做属性动画没有效果- 具体请看下面Button按钮的例子
1 | Button mButton = (Button) findViewById(R.id.Button); |
运行后,会看到其宽度并不会变化
为什么没有动画效果呢?我们来看View
的 setWidth
方法
1 | public void setWidth(int pixels) { |
上述问题解决方案
针对上述对象属性的set()
不是设置属性 或 根本没有set() / get()
的情况应该如何处理?
手动设置对象类属性的set()
& get()
。共有两种方法:
- 通过继承原始类,直接给类加上该属性的
get()
&set()
,从而实现给对象加上该属性的get()
&set()
- 通过包装原始动画对象,间接给对象加上该属性的
get()
&
set()
。即 用一个类来包装原始对象
对于第一种方法,在上面的例子已经说明;下面主要学第二种方法:通过包装原始动画对象,间接给对象加上该属性的get()& set()
还是采用上述 Button
按钮的例子
1 | public class MainActivity extends AppCompatActivity { |
发现这次就得到了我们想要的效果
Demo 地址
https://github.com/Commandercc/DemoEX/blob/master/AnimationDmeo3.zip