Android群英传之Android动画机制与使用技巧

1、视图动画

视图动画定义了透明度AlphaAnimation、旋转RotateAnimation、缩放ScaleAnimation、位移TranslateAnimation四种基本动画,还提供AnimationSet动画集合,混合使用多种动画。

原理
1. 每次绘制时,View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值
2. 调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧
3. 如果一次绘制结束,动画没有完成,就继续调用invalidate,启动下次绘制,知道动画绘制完成
另外
Animation也提供了对应得监听回调,监听动画开始、结束、重复事件

2、属性动画

视图动画改变的只是显示,并不能响应事件。而属性动画也可以让控件的对事件的监听转移位置。最常使用的就是AnimatorSet和ObjectAnimator。

1)ObjectAnimator

一般形式:

ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 300);
animator.setDuration(1000);
animator.start();

ObjectAnimator使用静态工厂方法生成动画对象,第一个参数为要控制的对象,第二个参数为要控制的属性值(该属性必须有get和set方法,因为实现原理就是通过Java的反射机制调用set函数修改对象属性值),第三个参数该属性变化的取值(也可以是数组)

常用的可以直接使用属性动画的属性包括

  1. translationX和translationY:控制view从它布局容器左上角坐标偏移的位置;
  2. rotation、rotationX和rotationY:控制view围绕支点进行2D和3D旋转;
  3. scaleX和scaleY:控制view围绕着它的支点进行2D缩放;
  4. pivotX和pivotY:控制支点位置,围绕这个支点进行旋转和缩放处理。默认情况下,支点是view的中心点;
  5. x和y:控制view在它的容器中的最终位置,它是最初的左上角坐标和translationX、translationY的累计和;
  6. alpha:控制透明度,默认是1(不透明)。

如果一个属性没有get、set方法怎么办?

a)自定义属性类或包装类,添加get、set方法

public class WrapperView {

    private View mView;

    public WrapperView(View mView){
        this.mView = mView;
    }

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

    public void setWidth(int width){
        mView.getLayoutParams().width = width;
        mView.requestLayout();
    }
}

b)通过ValueAnimator实现
本节后续会介绍

2)ValueAnimator

ObjectAnimator就是继承自ValueAnimator的,它是属性动画的核心,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!
    }
});

3)动画事件的监听

一个完整的动画有Start、Repeat、End、Cancle四个过程,Android提供接口监听这四个事件

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) {

            }
        });

大多数时候,只需要关心动画什么时候结束,就可以使用Android的简易适配器AnimatorListenerAdapter,其实它就是实现了接口AnimatorListener的抽象类,这样具体想监听那个具体事件就继承并重写那个方法即可

animator1.addListener(new AnimatorListenerAdapter() {
  @Override
   public void onAnimationEnd(Animator animation) {
       super.onAnimationEnd(animation);
   }
});

3)使用多个属性动画效果

a)PropertyValuesHolder

PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("rotation", 360);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(propertyBt, pvh1, pvh2, pvh3).setDuration(1000).start();

b)AnimatorSet

属性动画集合AnimatorSet:控制多个动画的协同工作方式,常用方法animatorSet.play().with().before().after()、playTogether、playSequentially等方法来精确控制动画播放顺序。

ObjectAnimator animator1 = ObjectAnimator.ofFloat(animBt, "rotation", 360);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(animBt, "scaleX", 1f, 0, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(animBt, "scaleY", 1f, 0, 1f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.playSequentially(animator1, animator2, animator3);
set.start();

更推荐使用AnimatorSet,既可以与PropertyValuesHolder一样实现几个属性动画同时使用,也可以定义几个动画的先后顺序

4)在xml中使用属性动画

在animator文件夹下定义属性动画


<objectAnimator xmlns:app="http://schemas.android.com/apk/res/android"
    app:duration="1000"
    app:propertyName="scaleX"
    app:valueFrom="1.0"
    app:valueTo="2.0"
    app:valueType="floatType">

objectAnimator>

在代码中使用

Animator anim = AnimatorInflater.loadAnimator(this, R.animator.anim);
anim.setTarget(xmlBt);
anim.start();

5)View的animate方法

属性动画的简写方式

imageView.animate().alpha(0).y(100).setDuration(1000)
        .setListener(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) {
            }
        }).start();

3、Android布局动画

ViewGroup增加View时的动画,使用以下代码打开系统默认的动画

android:animateLayoutChanges="true"

自定义布局动画

 LinearLayout ll = (LinearLayout) findViewById(R.id.layout_anim);
 ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
 sa.setDuration(2000);
 LayoutAnimationController lac = new LayoutAnimationController(sa, 0.5f);
 lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
 ll.setLayoutAnimation(lac);
  • LayoutAnimationController.ORDER_NORMAL顺序
  • LayoutAnimationController.ORDER_RANDOM顺序随机
  • LayoutAnimationController.ORDER_REVERSE反序

4、Interpolators(差值器)

定义动画变化速率,类似加速度。

5、自定义动画

创建自定义动画就是要实现它的applyTransformation的逻辑,不过通常还需要覆盖父类的initialize方法来实现初始化工作。

applyTransformation(float interpolatedTime, Transformation t)

第一个参数interpolatedTime差值器的时间因子
第二个参数Transformation,矩阵封装类,一般使用此类获取当前的矩阵对象:

final Matrix matrix = mTransformation.getMartix()

通过改变matrix对象,可将动画效果显示出来,matrix的变化基本可实现任何动画效果
模拟电视关闭动画

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

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final Matrix matrix = t.getMatrix();
        matrix.preScale(1, 1 - interpolatedTime, mCenterWidth, mCenterHeight);
    }
}

3D动画
使用android.graphics.Camera中的Camera类,它封装了OpenGL的3D动画。可以把Camera想象成一个真实的摄像机,当物体固定在某处时,只要移动摄像机就能拍摄到具有立体感的图像,因此通过它可以实现各种3D效果。

public class CustomAnim extends Animation {

    private int mCenterWidth;
    private int mCenterHeight;
    private Camera mCamera = new Camera();
    private float mRotateY = 0.0f;

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        setDuration(2000);// 设置默认时长
        setFillAfter(true);// 动画结束后保留状态
        setInterpolator(new BounceInterpolator());// 设置默认插值器
        mCenterWidth = width / 2;
        mCenterHeight = height / 2;
    }

    // 暴露接口-设置旋转角度
    public void setRotateY(float rotateY) {
        mRotateY = rotateY;
    }

    @Override
    protected void applyTransformation( float interpolatedTime, Transformation t) {
        final Matrix matrix = t.getMatrix();
        mCamera.save();
        mCamera.rotateY(mRotateY * interpolatedTime);// 使用Camera设置旋转的角度
        mCamera.getMatrix(matrix);// 将旋转变换作用到matrix上
        mCamera.restore();
        // 通过pre方法设置矩阵作用前的偏移量来改变旋转中心
        matrix.preTranslate(mCenterWidth, mCenterHeight);
        matrix.postTranslate(-mCenterWidth, -mCenterHeight);
    }
}

6、Android 5.X SVG矢量动画机制

挖坑待填-_-

你可能感兴趣的:(android,动画,Android基础,Android读书笔记)