Android属性动画
1、属性动画介绍
属性动画在指定的时间长度内更改属性(对象中的字段)值。 要为某些内容设置动画,请指定要设置动画的对象属性,例如对象在屏幕上的位置,要为其设置动画的时间长度以及要在其间设置动画的值。
属性动画扩展了Animator类,包含ObjectAnimator、ValueAnimator、AnimatorSet。
属性动画系统具有以下特征:
- 持续时间(Duration):指定动画的持续时间。默认长度为300毫秒。
- 时间插值(Time interpolation):指定如何计算属性值作为动画当前已用时间的函数。
- 重复计数和行为(Repeat count and behavior):指定是否在到达持续时间结束时重复动画以及重复动画的次数。您还可以指定是否要反向播放动画。将其设置为反向向前播放动画然后反复播放动画,直到达到重复次数。
- 动画设置(Animator sets):将动画分组为一起或按顺序或在指定延迟后播放的逻辑集。
- 帧刷新延迟(Frame refresh delay):指定刷新动画帧的频率。默认设置为每10毫秒刷新一次,但应用程序刷新帧的速度最终取决于系统整体的繁忙程度以及系统为基础计时器提供服务的速度。
2、属性动画和视图动画的区别
视图动画
仅为View对象设置动画的功能,例如视图的缩放和旋转,而不是背景颜色。
只修改了绘制视图的位置,而不是实际的视图本身。例如,如果您设置了一个按钮在屏幕上移动,则该按钮会正确绘制,但单击该按钮的实际位置不会更改,因此必须实现自己的逻辑来处理此问题。
属性动画
可以完全解决视图动画的约束,并可以为视图和非视图的任何属性设置动画,并且实际修改了对象本身。例如颜色,位置或大小,并可以定义动画的各个方面,例如多个动画的插值和同步。
具体怎样用,可以根据具体的场景来使用,例如,视图动画系统设置时间较短,编写代码较少。如果视图动画完成了您需要执行的所有操作,或者现有代码已按您希望的方式工作,则无需使用属性动画系统。
3、ObjectAnimator
属性动画框架中最重要的实行类,创建一个ObjectAnimator只需通过他的静态工厂类直接返回一个ObjectAnimator对象。是ValueAnimator的子类,它将ValueAnimator的计时引擎和值计算与为目标对象的命名属性设置动画的能力相结合。 这使得动画更容易,不再需要实现ValueAnimator.AnimatorUpdateListener,使得动画属性会自动更新。
- 代码实现
ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();
第一个参数是需要处理的view,第二个参数是操作的属性,最后一个是可变数组参数。
- 常用属性
第二个参数的属性 | 效果 |
---|---|
alpha | 表示View对象的alpha透明度。默认值是1(不透明),0代表完全透明 |
translationX | 沿X轴平移 |
translationY | 沿Y轴平移 |
scaleX | 沿X轴2D缩放 |
scaleY | 沿Y轴2D缩放 |
rotationX | 绕X轴2D和3D旋转 |
rotationY | 绕Y轴2D和3D旋转 |
rotation | 绕Z轴2D和3D旋转 |
- xml表示
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="scaleY"
android:repeatCount="1"
android:repeatMode="reverse"
android:startOffset="0"
android:valueFrom="1"
android:valueTo="3"
android:valueType="floatType"/>
- 自定义属性
如果属性没有get,set方法,可以自定义一个属性类或者包装类来间接的给这个属性增加get、set方法。
private static class ViewWrapper {
private View mTarget;
public ViewWrapper(View target) {
this.mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
调用:
ObjectAnimator.ofInt(new ViewWrapper(textView),"width",500).setDuration(5000).start();
4、ValueAnimator
通过指定一组int,float或color值来设置动画的持续时间,从而为动画的持续时间设置某种类型的值的动画。 您通过调用其工厂方法之一获取ValueAnimator:ofInt(),ofFloat()或ofObject()。 例如:
ValueAnimator animator =ValueAnimator.ofFloat(0,100);
animator.setTarget(textView);
animator.setDuration(500).start();
当start()方法运行时,ValueAnimator开始使用MyTypeEvaluator提供的逻辑在startPropertyValue和endPropertyValue之间计算动画的值,持续时间为1000毫秒。可以通过向ValueAnimator对象添加AnimatorUpdateListener来使用动画的值,如以下代码所示:
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
}
});
5、PropertyValuesHolder
PropertyValuesHolder对象可用于使用ValueAnimator或ObjectAnimator创建动画,这些动画可并行处理多个不同的属性。
ValueAnimator或ObjectAnimator底层都是通过PropertyValuesHolder来创建属性的,可以看看底层代码:
public void setPropertyName(@NonNull String propertyName) {
// mValues could be null if this is being constructed piecemeal. Just record the
// propertyName to be used later when setValues() is called if so.
if (mValues != null) {
PropertyValuesHolder valuesHolder = mValues[0];
String oldName = valuesHolder.getPropertyName();
valuesHolder.setPropertyName(propertyName);
mValuesMap.remove(oldName);
mValuesMap.put(propertyName, valuesHolder);
}
mPropertyName = propertyName;
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
多属性动画实现
PropertyValuesHolder pvhTX = PropertyValuesHolder.ofFloat("translationX", 300f);
PropertyValuesHolder pvhSX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvhSY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(textView, pvhTX, pvhSX, pvhSY).setDuration(1000).start();
6、动画事件监听
完整动画有Start、Repeat、End、Cancel四个过程,使用Animator.AnimatorListener来监听这四个过程
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
如果不想实现Animator.AnimatorListener接口的所有方法,则可以扩展AnimatorListenerAdapter类,而不是实现Animator.AnimatorListener接口。 AnimatorListenerAdapter类提供了可以选择覆盖的方法的空实现。例如:
animator.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
}
});
7、AnimatorSet
在许多情况下,您希望播放取决于另一个动画何时开始或结束的动画。 Android系统允许您将动画一起捆绑到AnimatorSet中,以便您可以指定是同时,按顺序还是在指定的延迟后启动动画。 您还可以将AnimatorSet对象嵌套在彼此中。可以通过playTogether、playSequentially、play.with、play.before、play.after来控制多个动画的协同工作方式。例如:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(textView, "translationX", 300f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(300);
animatorSet.playTogether(animator1);
animatorSet.start();
8、布局动画
是指作用在ViewGroup上,给它增加View时添加一个动画效果。使用LayoutTransition类为ViewGroup中的布局更改设置动画。 当您将ViewGroup中的视图添加或者删除它们时,或者当您使用VISIBLE,INVISIBLE或GONE调用View的setVisibility()方法时,ViewGroup中的视图可以通过显示和消失的动画。 添加或删除视图时,ViewGroup中的其余视图也可以设置为新位置的动画。可以使用以下代码开启布局动画。
android:animateLayoutChanges="true"
开启布局动画后会显示默认的动画效果,如果想自定义动画效果,可以使用LayoutAnimationController类自定义。
LinearLayout layout = findViewById(R.id.layout);
ScaleAnimation scale = new ScaleAnimation(0, 1, 0, 1);
scale.setDuration(1000);
LayoutAnimationController controller = new LayoutAnimationController(scale, 0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
layout.setLayoutAnimation(controller);
也可以通过调用setAnimator()并使用以下LayoutTransition常量之一传入Animator对象,在LayoutTransition对象中定义以下动画:
- APPEARING - 指示在容器中出现的项目上运行的动画。
- CHANGE_APPEARING - 指示由于容器中出现的新项目而在更改的项目上运行的动画。
- DISAPPEARING - 指示在从容器中消失的项目上运行的动画。
- CHANGE_DISAPPEARING - 指示由于项目从容器中消失而在更改的项目上运行的动画。
9、插值器(Interpolators)
插值器定义如何计算动画中的特定值作为时间的函数。例如,指定动画在整个动画中线性发生,这意味着动画在整个时间内均匀移动,或者指定动画以使用非线性时间,例如,在开始或结束时使用加速或减速动画。
Android系统在android.view.animation包中提供了一组通用插值器。也可以实现TimeInterpolator接口并创建自己的接口。
10、StateListAnimator
在视图状态发生变化时运行的动画。 此对象充当Animator对象的包装器,只要指定的视图状态(例如“按下”或“聚焦”)发生更改,就会调用该动画。可以使用根
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- the pressed state; increase x and y size to 150% -->
<item android:state_pressed="true">
<set>
<objectAnimator android:propertyName="scaleX"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="1.5"
android:valueType="floatType"/>
<objectAnimator android:propertyName="scaleY"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="1.5"
android:valueType="floatType"/>
</set>
</item>
<!-- the default, non-pressed state; set x and y size to 100% -->
<item android:state_pressed="false">
<set>
<objectAnimator android:propertyName="scaleX"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="1"
android:valueType="floatType"/>
<objectAnimator android:propertyName="scaleY"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="1"
android:valueType="floatType"/>
</set>
</item>
</selector>
使用
<Button android:stateListAnimator="@xml/animate_scale"/>