欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android中的属性动画

程序员文章站 2022-05-03 12:53:51
...

在属性动画出现之前,Android系统提供的动画只有帧动画和View动画。View动画提供了AlphaAnimationRotateAnimationTranslateAnimationScaleAnimation这四种动画方式,并提供了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中使用最多的就是AnimatorSetObjectAnimator配合:使用ObjectAnimator进行精细化的控制,控制一个对象和一个属性值,而多个ObjectAnimator组合到AnimatorSet形成一个动画。属性动画通过调用getset方法来真实的控制一个View的属性值。属性动画框架基本上可以实现所有的动画效果。

animator [ˈænɪmeɪtər] 卡通片绘制者,动画片制作者;鼓舞者;赋与生气者;娱乐体育活动组织者

1. ObjectAnimator

ObjectAnimator是属性动画最重要的类,创建一个ObjectAnimator只需要通过静态工厂类直接返回一个ObjectAnimator对象。 参数包括一个对象和对象的属性名字,但这个属性必须有getset方法,其内部会通过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;
  }
}

以下是属性动画的属性值:

  • translationXtranslationY:用来沿着X轴或者Y轴平移
  • rotationrotationXrotationY:用来围绕View支点进行旋转
  • pivotXpivotY:控制View对象的支点位置,围绕着这个支点进行旋转和缩放变换处理。默认该支点位置就是View对象的中心点
  • alpha:透明度,默认是1(不透明),0代表完全透明
  • xy:描述View对象在其容器中的最终位置

pivot [ˈpɪvət] 枢轴;中心点;中心

需要注意的是,在使用ObjectAnimator的时候,要操作的属性必须要有getset方法,不然ObjectAnimator就无法生效。 如果一个属性没有getset方法,也可以通过自定义一个属性类或者包装类来间接地给这个属性增加getset方法:

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();
    }
}

使用时只需要操作包类就可以调用getset方法了:

MyView myView = new MyView(mButton);ObjectAnimator.ofFloat(myView, "width", 500).setDuration(500).start();

2. ValueAnimator

ValueAnimator不提供任何动画效果,它更像一个数值发生器,用来产生一定规律的数字,从而让调用者控制动画的实现过程。 通常情况下,在ValueAnimatorAnimatorUpdateListener中监听数值的变化,从而完成动画的变换:

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100);
valueAnimator.setTarget(view);
valueAnimator.setDuration(1000).start();
valueAnimator.addUpdateListener(animation -> {
  Float mFloat = (Float) animation.getAnimatedValue();
});

3. 动画的监听

完整的动画具有startrepeatendcancel这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对象(ValueAnimatorObjectAnimator),将会返回一个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();
相关标签: android 动画