属性动画

2 分钟 阅读

1.Android动画的分类

  • 帧动画(Frame Animation):一系列的图片在同一个位置进行连贯的替换操作
  • 补间动画(Tween Animation):专门用于View,可以实现透明度、缩放、旋转和平移四种效果。
  • 属性动画(Property Animation):表面上效果和补间动画差不多。

补间动画和属性动画之间最大的差异: 补间动画只能作用于View,并且只能简单的去进行透明度、缩放、旋转和平移这四种动画,其他的比如去更改颜色,字体大小粗细等就无能为力了。但是属性动画,可以设置在任何对象上,并且可以去改变对象的属性。

2.属性动画准许定义的参数

  • 持续时间,默认为300ms。
  • 时间差值
  • 重复次数和行为
  • 动画集合(多个动画组合在一起)
  • 帧刷新延迟,默认10ms;但最终靠系统的整体繁忙程度和底层定时器服务的速度。

3.ObjectAnimator

ObjectAnimator是最常用的一个,其使用相对简单,只要设置几个参数,一个属性动画就实现了。 常用API

返回值类型 方法名 功能
ObjectAnimator clone() 返回一个该对象的副本
String getPropertyName() 获取被动画化的属性名称
Object getTarget() 被动画化的对象
static ObjectAnimator ofArgb(……) 改变颜色值
static ObjectAnimator ofFloat(……) 在浮点数值之间进行动画化
static ObjectAnimator ofInt(……) 在int值之间进行动画化
static ObjectAnimator ofMultiFloat(……) 多个参数设置器的浮点值进行动画化
static ObjectAnimator ofObject(……) 在对象之间动画化
void setAutoCancel(boolean cancel) 当启动具有相同目标和属性的任何其他ObjectAnimator时,autoCancel会控制是否自动取消ObjectAnimator。
ObjectAnimator setDuration(long duration) 设置动画持续时间
void setTarget(Object object) 设置要动画化的对象
void start() 开始动画

还用一些set方法,是把of系列的方法的参数拆开来设置了。详情可以去查看ObjectAnimator的API

例:执行单个动画

ObjectAnimator.ofFloat(btStart,"translationY",0f,500f)
            .setDuration(3000)
            .start();
//或者
objectAnimator = new ObjectAnimator();
objectAnimator.setFloatValues(10f,23f,43f,15f,55f);//多个参数
objectAnimator.setTarget(btStart);
objectAnimator.setPropertyName("translationY");
objectAnimator.setDuration(5000);
objectAnimator.start();

4.组合动画

同时运行动画

  1. 多个动画同时运行

方式一:

ObjectAnimator.ofFloat(image, "translationX", 0f, 500f).setDuration(3000).start();
ObjectAnimator.ofFloat(image, "translationY", 0f, 500f).setDuration(3000).start();
ObjectAnimator.ofFloat(image, "rotation", 0f, 360f).setDuration(3000).start();

方式二:

PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("translationX", 0f, 500f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("translationY", 0f, 500f);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("rotation", 0f, 360f);
ObjectAnimator.ofPropertyValuesHolder(image, holder1, holder2, holder3)
        .setDuration(3000)
        .start();

方式三:

ObjectAnimator animator1 = ObjectAnimator.ofFloat(image, "translationX", 0f, 500f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(image, "translationY", 0f, 500f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(image, "rotation", 0f, 360f);
AnimatorSet set = new AnimatorSet();
set.setDuration(3000);
set.playTogether(animator1, animator2, animator3);
set.start();
  1. 多个动画按一定顺序运行

方式一:使用AnimatorSet实现

ObjectAnimator animator1 = ObjectAnimator.ofFloat(image, "translationX", 0f, 500f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(image, "translationY", 0f, 500f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(image, "rotationX", 0f, 360f);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(image, "rotationY", 0f, 360f);
AnimatorSet set = new AnimatorSet();
set.play(animator3).before(animator2).after(animator1).with(animator4);
set.setDuration(3000);
set.start();

方式二:使用动画监听事件AnimatorListener实现

ObjectAnimator animator1 = ObjectAnimator.ofFloat(image, "alpha", 0f, 1f);
final ObjectAnimator animator2 = ObjectAnimator.ofFloat(image, "translationX", 0f, 500f);
final ObjectAnimator animator3 = ObjectAnimator.ofFloat(image, "translationY", 0f, 500f);
animator1.setDuration(3000);
animator2.setDuration(3000);
animator3.setDuration(3000);
// 设置属性动画的监听事件(使用AnimatorListener必须要监听所有四个事件)
animator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
        animator2.start();
    }
    @Override
    public void onAnimationEnd(Animator animation) {
        animator3.start();
    }
    @Override
    public void onAnimationCancel(Animator animation) {
    }
    @Override
    public void onAnimationRepeat(Animator animation) {
    }
});
animator1.start();

方法三:使用动画监听事件AnimatorListenerAdapter实现

ObjectAnimator animator1 = ObjectAnimator.ofFloat(image, "alpha", 0f, 1f);
final ObjectAnimator animator2 = ObjectAnimator.ofFloat(image, "translationX", 0f, 500f);
final ObjectAnimator animator3 = ObjectAnimator.ofFloat(image, "translationY", 0f, 500f);
animator1.setDuration(3000);
animator2.setDuration(3000);
animator3.setDuration(3000);
// 设置属性动画的监听事件(使用AnimatorListenerAdapter可以选择不监听所有事件)
animator1.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        animator3.start(); // 在animator1执行完后执行animator3
    }
    @Override
    public void onAnimationStart(Animator animation) {
        animator2.start(); //在animator1执行的同时执行animator2
    }
});
animator1.start();

5.ValueAnimator

和ObjectAnimator使用方法基本相同,不同之处在于ValueAnimator不能指定运行动画的对象.从而必须设置一个动画监听器,通过不断监听当前动画运行到的属性值来动态的进行处理.

ValueAnimator animator = ValueAnimator.ofInt(0, 100); // 产生一个从0到100变化的整数的动画
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Integer value = (Integer) animation.getAnimatedValue(); // 动态的获取当前运行到的属性值
        ((Button) view).setText(value + "");
    }
});
animator.start(); // 开始播放动画

6.使用XMl编写动画

过去的补间动画可以通过XML的方式编写,属性动画也可以编写到XML文件中。编写到XML文件中的一个好处是可以方便的实现动画的重用。

  我们需要在项目的res目录下创建一个名为animator的文件夹,在这个文件夹中定义动画。animator动画XML文件中可以包括以下三种标签:

  • <animator>:相当于JAVA代码中的ValueAnimator;
  • <objectAnimator>:相当于JAVA代码中的ObjectAnimator;
  • <set>:相当于JAVA代码中的AnimatorSet。

7.TypeEvaluate

作用是告诉动画如何从初始值过渡到结束值。

ObjectAnimator.ofFloat()中默认的TypeEvaluate是其子类FloatEvaluate,其效果是使动画在初始值与结束值之间进行平滑的过度.

public class FloatEvaluator implements TypeEvaluator<Number> {
    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}

其实现方法evaluate的第一个参数为动画执行进度,相当于百分比,值在0~1之间;第二个参数为动画开始值;第三个参数是动画结束值.

TypeEvaluate使用示例:

animator = ValueAnimator.ofObject(new TypeEvaluator() {
            @Override
            public Object evaluate(float fraction, Object startValue, Object endValue) {
                int start = Integer.parseInt((String) startValue);
                int end = Integer.parseInt((String) endValue);
                int result = (int) (start + fraction * (end - start));
                return result + "%";
            }
        }, "0", "100");
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                String value = (String) animation.getAnimatedValue();
                btStart.setText(value);
            }
        });
animator.setDuration(6000);
animator.start();

8.Interpolator

作用是控制动画的变化速率. 系统提供的有:

1) BounceInterpolator:弹跳效果; 2) AccelerateInterpolator:逐渐加速; 3) DecelerateInterpolator:逐渐减速; 4) AccelerateDecelerateInterpolator:先加速后减速; 5) OvershootInterpolator:到达目标点时“跑过头了”,再返回到目标点; 6) AnticipateInterpolator:移动之前先向后“助跑”; 7) AnticipateOvershootInterpolator:OvershootInterpolator和AnticipateInterpolator的组合效果; 8) CycleInterpolator:对于指定的动画,正向做一遍,反响做一遍;

我们也可以通过继承TimeInterpolator继承我们自己的插值器,或者是通过继承他的某些子类.TimeInterpolator接口中有一个抽象方法setInterpolation(),方法中有一个参数input,这个参数的值在整个动画过程中从0匀速变化到1,也就是相当于一个百分比,指示当前动画播放到哪了。

9.ViewPropertyAnimator

ViewPropertyAnimator是在Android 3.1的API中新加入的更加易懂、更加便于使用的动画API。

属性动画虽然可以对所有对象添加动画效果,但我们在使用过程中还是以对View使用动画为多,因此Google为我们提供了一个ViewPropertyAnimator,让我们可以简单的调用这套API来单独为View设置动画。

ViewPropertyAnimator让我们可以使用链式编程,一行代码为一个View对象设置属性,示例代码如下:

textView.animate()
        .translationX(200)
        .translationY(200)
        .setDuration(2000)
        .setInterpolator(new BounceInterpolator())
        .start();

当我们对一个View对象使用animate()方法时,就返回了一个ViewPropertyAnimator对象,这个对象中支持所有补间动画的API以及属性动画的API。ViewPropertyAnimator是默认执行的动画,也就是说,我们不需要在最后调用start()方法,动画也会自动播放。