Android中的属性动画
在属性动画出现之前,Android
系统提供的动画只有帧动画和View
动画。View
动画提供了AlphaAnimation
、RotateAnimation
、TranslateAnimation
、ScaleAnimation
这四种动画方式,并提供了AnimationSet
动画集合来混合使用多种动画。View
动画不具有交互性,比如说当某个元素发生了View
动画后,其响应事件的位置仍旧在动画进行前的地方, 所以View
动画只能做普通的动画效果,要避免交互操作,但是它的效率比较高,使用方便。
animation [ˌænɪˈmeɪʃn] 动画 alpha [ˈælfə] 希腊字母的第一个字母;开端;最初 rotate [ˈroʊteɪt] 旋转;循环
translate [trænzˈleɪt; trænsˈleɪt] 转化 scale [skeɪl] 比例
Android 3.0
之后,谷歌推出了新的动画框架——属性动画Animator
。在Animator
中使用最多的就是AnimatorSet
和ObjectAnimator
配合:使用ObjectAnimator
进行精细化的控制,控制一个对象和一个属性值,而多个ObjectAnimator
组合到AnimatorSet
形成一个动画。属性动画通过调用get
、set
方法来真实的控制一个View
的属性值。属性动画框架基本上可以实现所有的动画效果。
animator [ˈænɪmeɪtər] 卡通片绘制者,动画片制作者;鼓舞者;赋与生气者;娱乐体育活动组织者
1. ObjectAnimator
ObjectAnimator
是属性动画最重要的类,创建一个ObjectAnimator
只需要通过静态工厂类直接返回一个ObjectAnimator
对象。 参数包括一个对象和对象的属性名字,但这个属性必须有get
和set
方法,其内部会通过Java
反射机制来调用set
方法修改对象的属性值:
CustomView mCustomView = findViewById(R.id.custom_view);
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mCustomView, "translationX", 200);
objectAnimator.setDuration(2000);
objectAnimator.start();
通过ObjectAnimator
的静态方法,创建一个ObjectAnimator
对象,查看ObjectAnimator.java
的静态方法ofFloat()
:
public final class ObjectAnimator extends ValueAnimator {
// 1. Object target:要操作的对象
// 2. String propertyName:要操作的属性
// 3. float... values:可变的float类型数组,表示该属性变化的取值过程
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
}
以下是属性动画的属性值:
translationX
和translationY
:用来沿着X
轴或者Y
轴平移rotation
、rotationX
、rotationY
:用来围绕View
支点进行旋转pivotX
和pivotY
:控制View
对象的支点位置,围绕着这个支点进行旋转和缩放变换处理。默认该支点位置就是View
对象的中心点alpha
:透明度,默认是1
(不透明),0
代表完全透明x
和y
:描述View
对象在其容器中的最终位置
pivot [ˈpɪvət] 枢轴;中心点;中心
需要注意的是,在使用ObjectAnimator
的时候,要操作的属性必须要有get
、set
方法,不然ObjectAnimator
就无法生效。 如果一个属性没有get
、set
方法,也可以通过自定义一个属性类或者包装类来间接地给这个属性增加get
和set
方法:
public class MyView {
private View mTarget;
private MyView(View target) {
this.mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
使用时只需要操作包类就可以调用get
、set
方法了:
MyView myView = new MyView(mButton);ObjectAnimator.ofFloat(myView, "width", 500).setDuration(500).start();
2. ValueAnimator
ValueAnimator
不提供任何动画效果,它更像一个数值发生器,用来产生一定规律的数字,从而让调用者控制动画的实现过程。 通常情况下,在ValueAnimator
的AnimatorUpdateListener
中监听数值的变化,从而完成动画的变换:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100);
valueAnimator.setTarget(view);
valueAnimator.setDuration(1000).start();
valueAnimator.addUpdateListener(animation -> {
Float mFloat = (Float) animation.getAnimatedValue();
});
3. 动画的监听
完整的动画具有start
、repeat
、end
、cancel
这4个过程。Android
也提供了AnimatorListenerAdapter
来让我们进行选择必要的事件进行监听:
ObjectAnimator animator = ObjectAnimator.ofFloat(mCustomView, "alpha", 1.5f);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
}
});
4. 组合动画——AnimatorSet
AnimatorSet
类提供了一个play()
方法,如果我们向这个方法中传入一个Animator
对象(ValueAnimator
或ObjectAnimator
),将会返回一个AnimatorSet.Builder
的实例,以下是AnimatorSet.play
方法:
public final class AnimatorSet extends Animator implements AnimationHandler.AnimationFrameCallback {
public Builder play(Animator anim) {
if (anim != null) {
return new Builder(anim);
}
return null;
}
}
在play()
方法中创建了一个AnimatorSet.Builder
类,这个Builder
类是AnimatorSet
的内部类:
public class Builder {
private Node mCurrentNode;
Builder(Animator anim) {
mDependencyDirty = true;
mCurrentNode = getNodeForAnimation(anim);
}
public Builder with(Animator anim) {
Node node = getNodeForAnimation(anim);
mCurrentNode.addSibling(node);
return this;
}
public Builder before(Animator anim) {
Node node = getNodeForAnimation(anim);
mCurrentNode.addChild(node);
return this;
}
public Builder after(Animator anim) {
Node node = getNodeForAnimation(anim);
mCurrentNode.addParent(node);
return this;
}
public Builder after(long delay) {
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(delay);
after(anim);
return this;
}
}
Builder
类采用了建造者模式,每次调用方法时都返回Builder
自身用于继续构建。AnimatorSet.Builder
中包括以下4种方法:
after(Animator anim)
:将现有的动画插入到传入的动画之后执行after(long delay)
:将现有动画延迟指定毫秒后执行before(Animator anim)
:将现有动画插入到传入的动画之前执行with(Animator anim)
:将现有动画和传入的动画同时执行
AnimatorSet
正是通过这几种方法来控制动画播放顺序的:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mCustomView, "translationX", 0.0f, 200.0f, 2.0f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mCustomView, "scaleX", 1.0f, 2.0f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mCustomView, "rotationX", 0.0f, 90.0f, 0.0f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.play(animator1).with(animator2).after(animator3);
set.start();
5. 组合动画——PropertyValuesHolder
property [ˈprɑːpərti] 特性,性质
使用PropertyValuesHolder
类最多也只能是多个动画一起执行:
PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.5f);
PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0f, 90.0f, 0.0f);
PropertyValuesHolder valuesHolder3 = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.3f, 1.0F);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mCustomView, valuesHolder1, valuesHolder2, valuesHolder3);
objectAnimator.setDuration(2000).start();
以下是ObjectAnimator.ofPropertyValuesHolder
的源码:
public final class ObjectAnimator extends ValueAnimator {
// 1. Object target:动画的目标对象
// 2. PropertyValuesHolder... values:ropertyValuesHolder的实例
public static ObjectAnimator ofPropertyValuesHolder(Object target,
PropertyValuesHolder... values) {
ObjectAnimator anim = new ObjectAnimator();
anim.setTarget(target);
anim.setValues(values);
return anim;
}
}
6. 在XML
中使用属性动画
属性动画也可以直接写在.xml
文件中。在res
文件中新建animator
文件,在里面新建一个scale.xml
:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType">
</objectAnimator>
在程序中引用xml
定义的属性动画:
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scale);animator.setTarget(mCustomView);animator.start();
推荐阅读
-
Python中动态获取对象的属性和方法的教程
-
Android开发中总结的Adapter工具类【附完整源码下载】
-
Android数据传输中的参数加密代码示例
-
Android开发中button按钮的使用及动态添加组件方法示例
-
Android自定义可点击的ImageSpan并在TextView中内置View
-
Android 中CheckBox的isChecked的使用实例详解
-
Android中pendingIntent与Intent的深入分析
-
JavaScript中的原型prototype属性使用详解
-
JavaScript中Number.MIN_VALUE属性的使用示例
-
JavaScript中Number.MAX_VALUE属性的使用方法