Android Property Animation

概述


  • 属性动画,顾名思义-动态改变对象的属性,以此变化来产生某种效果。 这里的对象可是任何对象,并不限定是View控件。

  • 属性动画是Android 3.0(API 11)增加的,为何增加?有何意义?

    • 你一定还记得在view animation 中,交互不友好(比如view的位置改变了,但是点击事件还在原来的位置)
    • view animation 能让view动起来的效果有限,属性动画可是打着能改变任何对象的任何属性出场的,这样就可以实现复杂高级效果了。
  • 系统为我们提供了属性动画哪些用法?出了具体表现在这些类,也支持XML中定义使用。

    • ObjectAnimator
    • PropertyHolder
    • ValueAnimator
    • AnimatorSet
    • Animator.AnimatorListener
    • ValueAnimator.AnimatorUpdateListener
  • 属性动画中也要用到view动画中的差值器等API,也独有估值器

ObjectAnimator


Android Property Animation_第1张图片
ObjectAnimator继承关系

在这个类中,通过调用ObjectAnimator的工厂方法,传入对应的参数即可,举个简单的用法来看具体怎么使用

属性动画1.gif

这样的效果用属性动画也是非常容易实现的

 ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageview, "translationX", 0f, imageview.getWidth());
 // 指定一个时间差值器(TimeInpolator),ObjectAnimator默认的是LinearInpolator
 objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator());
 objectAnimator1.setDuration(1000);
 objectAnimator1.start();

关于ofFloat(Object target, String propertyName, float... values)
第一个参数是要操纵的对象,第二个是操纵对象的属性名,第三个是一个可变数组参数,表示属性的取值变化的过程

列举view的一些常见可以直接用的属性值
view偏移量: translationX 、translationY
view2D和3D旋转角度: rotation、rotationX、rotationY
view的2D缩放比例: scaleX、 scaleY
view的旋转和缩放的中心点,默认是view的中心点:pivotX、pivotY
view的坐标: x 、y
view的透明度: alpha

值得注意的是ObjectAnimator

  • 操纵的属性必须具有set(),因为ObjectAnimator在动态改变属性的过程中,会去通过set方法来改变这个属性。如果操纵的属性没有set方法,官方给出三种建议:
    • 如果你有权限的话就去给这个属性添加一个set方法
    • 可以通过自定义一个属性类或者包装类,来间接给这个属性增加set方法
    • 使用ValueAnimator来代替
  • 对于这个可变参数,values...如果仅仅设置了一个参数,会被认为这个值是变化过程的结束值。此刻ObjectAnimator会自动去通过get()来获得变化的起始值,这时就要求操作的属性必须具有get方法

这里我们举个例子,操作一个自定义的对象

 public class Person {
    private int age;

    public void setAge(int age) {
        this.age = age;
        Log.d("age", "set年龄" + age);
    }

    public int getAge() {
        Log.d("age", "get年龄" + age);
        return age;

    }
}

这个时候我们去动画的改变它

 ObjectAnimator objectAnimator;
 // 1.属性动画可以对任意一个对象的属性动态改变
 objectAnimator = ObjectAnimator.ofInt(new Person(), "age",5,  8);
 objectAnimator.start();

观察这个时候的log

Android Property Animation_第2张图片
log1

和我们预想的一样,动态改变了这个年龄值,哈哈

如果我们对可变参数只设置一个参数呢?

 ObjectAnimator objectAnimator;
// 1.属性动画可以对任意一个对象的属性动态改变
objectAnimator = ObjectAnimator.ofInt(new Person(), "age", 4);
objectAnimator.start();

这个时候的log 显示表明调用了get方法获得初始值

Android Property Animation_第3张图片
log2

虽然上面这个改变属性值没有实际意义,但是很清晰的展示了属性动画的魅力和变化过程。

你对为什么一个数值打印那么多遍感到很奇怪?
其实这就是属性动画中有估值器(Evaluator)这个概念,这里我给采用的是ofInt 对应的其实是IntEvaluator,这是ObjectAnimator内部会去判断,可以去源码中查看。
同理如果ofFloat对应的就是FloatEvaluator
当然你也可以ofObject传入自己想要的估值器

那么这个时候你把Personage属性改成float, 并且动画采用ofFloat,结果你会发现会一步一步接近最后的值。

Android Property Animation_第4张图片
反复调用set方法,一步步接近终值

PropertyValuesHolder


如果同时改变多个属性呢?

可以直接构造多个ObjetAnimator 然后调用start. 因为他们是异步的,这些动画会同时执行

  objectAnimator1.setInterpolator(new AccelerateDecelerateInterpolator());
  objectAnimator1.setDuration(1000);
  ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageview, "translationY", 0f, imageview.getHeight());
  objectAnimator2.setInterpolator(new AccelerateDecelerateInterpolator());
  objectAnimator2.setDuration(1000);
  ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageview, "rotationX", 0f, 360);
  objectAnimator3.setInterpolator(new AccelerateDecelerateInterpolator());
  objectAnimator3.setDuration(2000);
  objectAnimator1.start();
  objectAnimator2.start();
  objectAnimator3.start();;

还可以使用PropertyValuesHolder,然后调用的ObjectAnimator.ofPropertyValuesHolder

PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0f,imageview.getWidth());
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("translationY",0f,imageview.getHeight());
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("rotationX",0f,360f);
ObjectAnimator.ofPropertyValuesHolder(imageview, p1,p2,p3).setDuration(2000).start();

在上面的例子中,那如果我想控制他们的播放顺序呢?

AnimatorSet


同时X,Y平移后旋转

这个效果是先同时x和y方向平移动画,然后在执行旋转

    ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageview, "translationX", 0f, imageview.getWidth());
    ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageview, "translationY", 0f, imageview.getHeight());
    ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageview, "rotationX", 0f, 360);
    AnimatorSet set = new AnimatorSet();
    set.setDuration(2000);
    set.setInterpolator(new LinearInterpolator());
    //set.playTogether(objectAnimator1,objectAnimator2, objectAnimator3);
    //set.playSequentially(objectAnimator1,objectAnimator2, objectAnimator3);
    set.play(objectAnimator1).with(objectAnimator2).before(objectAnimator3); objectAnimator3);
    set.start();

可以将注释部分观察效果。AnimatorSet需要说明几点:

  • playSequentially是单独顺序播放
  • play配合withbeforeafter来按照这些规则播放动画
  • playTogether 动画同时播放

ValueAnimator的使用


通过上面的那个类关系图,ValueAnimatorObjectAnimator的父类,实际上ObjectAnimator是更加具体化了ValueAnimator,实现了一系列的既定效果,更加方便的使用。那么上文提到如果一个属性没有set方法可以用ValueAnimator来代替.

什么意思呢?其实就是说ValueAnimator,它并不要求你非要指定什么属性,注重的是值的变化,然后可以监听这些值的变化过程,从而自己来根据这些值,产生你自己需要的效果。比如你要做一个计时器,这个时候你可以ofInt在监听里面去设置UI 显示倒计时的数值即可。

这里看一下如何监听等常规思路:

ValueAnimator valueAnimator = ValueAnimator.ofInt(1,15);// ValueAnimator ,ofInt,ofFloat,ofObject
   
    // valueAnimator.setEvaluator(new IntEvaluator()); // 设置估值器
    valueAnimator.setEvaluator(new TypeEvaluator() {
        @Override
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            // 这里自定义了一个估值器,就是在int估值器的基础上加一个1
            int startInt = startValue;
            return (int)(startInt + fraction * (endValue - startInt)+1);
        }
    });
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
           Log.d("smart","变化的值:" +animation.getAnimatedValue());
        }
    });
    valueAnimator.setDuration(3000);
    valueAnimator.start();

估值器

  • 系统定义的估值器:

    • IntEvaluator 计算整型
    • FloatEvaluator 计算float型
    • ArgbEvaluator 计算颜色
    • TypeEvaluator 是一个接口,自定义估值器需要实现它
  • 如何自定义一个估值器

      public interface TypeEvaluator {
    
          public T evaluate(float fraction, T startValue, T endValue);
      }
    

    实现这个接口,确定泛型的返回值T。

至此 ,属性动画的基本概念叙述完毕!

你可能感兴趣的:(Android Property Animation)