Android动画机制与使用技巧

`# 前言

  • Android群英传读书笔记
    // SVG部分待补充

目录

Android动画机制与使用技巧_第1张图片
Android动画机制与使用技巧.png

Android View动画框架

  • Animation框架定义了几种常见动画
    • 透明度 AlphaAnimation
    • 旋转 RotateAnimation
    • 缩放 ScaleAnimation
    • 位移 TranslateAnimation
    • 动画合集 AnimatorSet
  • 实现原理
    • 每次绘制视图View所在ViewGroup中drawChild函数获取该View的Animation的Transformation值
    • 调用canvas.concat(transformToApply.getMatrix())
    • 通过矩阵运算完成动画帧
    • 如果动画没有完成,就继续调用invalidate()函数,启动下次绘制来驱动动画
    • 从而完成整个动画的绘制
  • 缺点:不具备交互性,视图动画结束,但响应事件位置不变
  • 优点:效率高,使用方便

Android属性动画

  • 可以响应事件
  • 通常是AnimatorSet和ObjectAnimator配合
  • ObjectAnimator能够自动驱动

ObjectAnimator

  • 创建一个ObjectAnimator只需要通过它的静态工厂类直接返回一个ObjectAnimator对象
  • 参数包括一个对象和对戏那个的属性名,但这个属性必须有Set和Get方法,内部会通过反射机制调用Set方法修改对象属性值
// 简单的位移动画
ObjectAnimator animator = ObjectAnimator.ofFloat(
  view,
  "translationX",
  300
);
animator.setDuration(300);
animator.start();
属性 作用
translationX、translationY 作为增量控制View对象从它布局容器的左上角坐标偏移的位置
rotation、rotationX、rotationY 控制View对象围绕支点进行2D和3D旋转
scaleX、scaleY 控制View对象围绕支点进行2D缩放
pivotX、pivotY 控制View对象的支点位置,围绕这个支点进行旋转和缩放变换处理,默认情况下,该支点的位置就是View对象的中心点
x、y 描述View对象在他容器的最终位置,是最初左上角坐标和translationX、translationY值得累计和
alpha View对象的透明度,默认为1,0为完全透明
  • 属性动画的机制是通过反射调用Set和Get方法,如果一个属性没有Get和Set方法应该怎么办?google在应用层提供了两种解决方法
    • 通过自定义一个属性类或者包装类来间接的给这个属性增加get、set方法
    • 通过ValueAnimator来实现
private static class WrapperView {
  private View mTraget;

  public WrapperView(View target) {
    mTarget = target;
  }

  public int getWidth() {
    return mTarget.getLayoutParams().width;
  }

  public void setWidth(int width) {
    mTarget.getLayoutParams().width = width;
    mTarget.requestLayout();
  }
}
  • 通过上面的方法给属性动画包装一层,并提供了Get、Set方法
ViewWrapper wrapper = new ViewWrapper(mButton);
ObjectAnimator.ofInt(wrapper,"width",500).setDuration(5000).start();

PropertyValuesHolder

  • 针对同一个对象的多个属性,可以使用PropertyValuesHolder
PropertyValuesHolder pv1 = PropertyValuesHolder.ofFloat("translationX", 300);
PropertyValuesHolder pv2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pv3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(view, pv1,pv2,pv3).setDuration(2000).start();

ValueAnimator

  • ObjectAnimator继承自ValueAnimator
  • 可以看作一个数值发生器,用来产生有规律的数字
  • AnimatorUpdateListener监听数值变换
ValueAnimator animator = ValueAnimator.ofFloat(0,100);
animator.setTarget(view);
animator.setDuration(1000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
    @Override 
    public void onAnimationUpdate(ValueAnimator animation) { 
    Float value = (Float) animation.getAnimatedValue(); 
    //do the animation! 
  }
});

动画事件监听

  • 一个完整的动画具有Start、Repeat、End、Cancel四个过程
  • 当然一般用到最多的是End监听
 ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0.5f);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationCancel(Animator animation) {
                super.onAnimationCancel(animation);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                super.onAnimationRepeat(animation);
            }

            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
            }

        });

AnimatorSet

  • 同样是对一个控件添加多个动画,AnimatorSet比PropertyValuesHolder多了精确控制动画顺序的功能
  • 还是上面的例子
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "translationX", 300f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f, 1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(2000);
set.playTogether(animator1,animator2,animator3);
set.start();
API 作用
playTogether() 一起播放
playSequentially() 顺序播放
animSet.play(anim1).with(anim2) anim1和anim2一起播放
animSet.play(anim1).before(anim2) anim1在anim2之前播放
animSet.play(anim1).after(anim2) anim1在anim2之后播放

XML中使用属性动画



  • 使用
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scalex);
anim.setTarget(view);
anim.start();

View的animate方法

  • Android3.0之后,View自带animate方法直接驱动属性动画(相当于简写方法)
view.animate()
                .alpha(0)
                .y(300)
                .setDuration(3000)
                .withStartAction(new Runnable() {
                    @Override
                    public void run() {

                    }
                })
                .withEndAction(new Runnable() {
                    @Override
                    public void run() {

                    }
                }).start();

Android布局动画

  • 作用在ViewGroup上,给ViewGroup增加View时添加一个动画过渡效果
  • 最简单的例子
android:animateLayoutChanges="true"
  • 或者使用LayoutAnimationController类自定义一个View过渡效果
    • LayoutAnimationController.ORDER_NORMAL-- 顺序
    • LayoutAnimationController.ORDER_RANDOM-- 随机
    • LayoutAnimationController.ORDER_REVERSE-- 逆序
LinearLayout ll = (LinearLayout)findViewById(R.id.ll);
// 设置过渡动画
ScaleAnimation sa = new ScaleAnimation(0,1,0,1);
sa.setDuration(2000);
// 设置布局动画的显示属性
LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5F);
lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
// 为ViewGroup设置布局动画
ll.setLayoutAnimation(lac);


自定义动画

  • 实现applyTransformation即可
  • 根据情况覆盖父类initialize方法实现一些初始化工作
/**
  * 电视机关闭效果
  */
public class CustomTV extends Animation {

    // 中心点坐标
    private int mCenterWidth;
    private int mCenterHeight;

    /**
      * 实现初始化操作
      */
    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(1000);
        // 动画结束后保留状态
        setFillAfter(true);
        // 设置默认插值器
        setInterpolator(new AccelerateInterpolator());
        mCenterWidth = width / 2;
        mCenterHeight = height / 2;
    }

    /**
      * 参数1:interpolatedTime:插值器的时间因子,由动画当前完成的百分比和当前时间所对应的插值计算得来,取值范围0到1.0
      * 参数2:Transformation:矩阵的封装类,一般使用这个类获得当前的矩阵对象
      */
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        // 获得当前矩阵对象
        final Matrix matrix = t.getMatrix();
        // 通过改变matrix对象,实现动画效果
        matrix.preScale(1, 1 - interpolatedTime, mCenterWidth, mCenterHeight);
    }
}

你可能感兴趣的:(Android动画机制与使用技巧)