zoukankan      html  css  js  c++  java
  • Android动画

    Android的动画可以分为三种:View动画、帧动画和属性动画,其实帧动画也属于View动画的一种,只不过它和平移、旋转等常见的View动画在表现形式上不同而已。

    View动画通过对场景里的对象不断做图像变换(平移、缩放、旋转、透明度)从而产生动画效果,它是一种渐进式动画。

    帧动画通过数序播放一系列图像从而产生动画效果,可以简单理解为图片切换动画,图片过多过大就会导致OOM(Out Of Memory,指的是kernel因分配不出内存而报的错误)。

    属性动画通过动态的改变对象的属性从而达到动画效果。

    一、View动画

    View动画的四种变换效果对应着Animation的四个子类:TranslateAnimation、ScaleAnimation、RotateAnimation、AlphaAnimation.这四种动画既可以通过XML定义,也可以通过代码来动态创建,建议采用XML来定义动画。

    名称 标签 子类 效果
    平移动画 <translate> TranslateAnimation 移动View
    缩放动画 <scale> ScaleAnimation 放大缩小View
    旋转动画 <rotate> RotateAnimation 旋转View
    透明度动画 <alpha> AlphaAnimation 改变View的透明度
    <!--
      android:interpolator
      设置动画集合所采用的插值器,默认值为@android:anim/accelerate_decelerate_interpolator
    
      android:shareInterpolator
      Boolean. 表示集合中的动画是否共享集合的插值器。当值为true且集合没有设置插值器,
      此时集合中的动画就会使用默认的插值器@android:anim/accelerate_decelerate_interpolator,
      但是你也可以为集合中的动画单独指定所需的插值器。
    -->
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@[package:]anim/interpolator_resource"
        android:shareInterpolator=["true" | "false"] >
        <alpha
            android:fromAlpha="float"
            android:toAlpha="float" />
        <scale
            android:fromXScale="float"
            android:toXScale="float"
            android:fromYScale="float"
            android:toYScale="float"
            android:pivotX="float"
            android:pivotY="float" />
        <translate
            android:fromXDelta="float"
            android:toXDelta="float"
            android:fromYDelta="float"
            android:toYDelta="float" />
        <rotate
            android:fromDegrees="float"
            android:toDegrees="float"
            android:pivotX="float"
            android:pivotY="float" />
        <set>
            ...
        </set>
    </set>

    <set>标签表示补间动画的集合,对应于AnimationSet类,所以上面语法中的<set>标签可以包含多个补间动画的标签;并且补间动画的集合中还可以包含补间动画的集合。

    1、translate 位置转移动画

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:duration="2000"
            android:fromXDelta="30"
            android:fromYDelta="30"
            android:toXDelta="400"
            android:toYDelta="300" />
    </set>

    代码方式:

    Animation loadAnimation = new TranslateAnimation(30.0f, 400.0f, 30.0f, 300.0f);
    loadAnimation.setDuration(2000);
    imageView.startAnimation(loadAnimation);

    2、scale 尺寸伸缩动画

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <scale
            android:duration="2000"
            android:fillAfter="false"
            android:fromXScale="0.0"
            android:fromYScale="0.0"
            android:interpolator="@android:anim/accelerate_decelerate_interpolator"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toXScale="1.4"
            android:toYScale="1.4" />
    </set>

    代码方式:

    Animation loadAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    loadAnimation.setDuration(2000);
    imageView.startAnimation(loadAnimation);

    3、rotate 旋转动画

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <rotate
            android:duration="2000"
            android:fromDegrees="0"
            android:interpolator="@android:anim/accelerate_decelerate_interpolator"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toDegrees="+350" />
    </set>

    代码方式:

    Animation loadAnimation = new RotateAnimation(0.0f, +350.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    loadAnimation.setDuration(2000);
    imageView.startAnimation(loadAnimation);

    4、alpha 透明度动画

    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <alpha
            android:duration="2000"
            android:fromAlpha="0.0"
            android:toAlpha="1.0" />
    </set>

    代码方式:

    Animation loadAnimation = new AlphaAnimation(0.0f, 1.0f);
    loadAnimation.setDuration(2000);
    imageView.startAnimation(loadAnimation);

    5、自定义动画

    自定义动画需要集成Animation抽象类,然后重写它的initialize和applyTransformation方法,

    在initialize方法中做一些初始化工作,在applyTransformation中进行相应的矩阵变换即可,很多时候需要采用Camera来简化矩阵变换的过程(需要数学知识)。

    二、帧动画

    帧动画是顺序播放一组预定义好的图片,类似于电影播放。系统提供了AnimationDrawable类来使用帧动画。

    frame帧动画

    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="true" >
        <item
            android:drawable="@drawable/pic01"
            android:duration="1000"/>
        <item
            android:drawable="@drawable/pic02"
            android:duration="1000"/>
        <item
            android:drawable="@drawable/pic03"
            android:duration="1000"/>
    </animation-list>

    xml帧动画使用代码:

    imageView.setImageResource(R.drawable.pic_frame);
    AnimationDrawable animation = (AnimationDrawable) imageView.getDrawable();
    animation.setOneShot(false);//循环
    animation.start();

    帧动画的使用比较简单,但是比较容易引起OOM,所以在使用的时候尽量避免使用过多尺寸较大的图片。

    三、属性动画

    属性动画是API11(Android3.0)加入的新特性,有ValueAnimator、ObjectAnimator和AnimatorSet等概念,通过它们可以实现绚丽的动画。

    其中ObjectAnimator继承自ValueAnimator,AnimatorSet是属性动画集,可以定义一组动画。

    只要某个类具有属性(即该类含有某个字段的set和get方法),那么属性动画框架就可以对该类的对象进行动画操作。

    属性动画框架工作原理:
    1 在创建属性动画时如果没有设置属性的初始值,此时Android系统就会通过该属性的get方法获取初始值,所以在没有设置属性的初始值时,必须提供该属性的get方法,否者程序会Crash。
    2 在动画播放的过程中,属性动画框架会利用时间流逝的百分比获取属性值改变的百分比(时间插值器TimeInterpolator),接着利用获取的属性值改变的百分比获取改变后的属性值(类型估值器TypeEvaluator)。
    3 通过该属性的set方法将改变后的属性值设置到对象中。

    <!--
      android:ordering
      该属性有如下两个可选值:
      together:表示动画集合中的子动画同时播放。
      sequentially:表示动画集合中的子动画按照书写的先后顺序依次播放。
      该属性的默认值是together。
    -->
    <set
      android:ordering=["together" | "sequentially"]>
    
        <objectAnimator
            android:propertyName="string"
            android:duration="int"
            android:valueFrom="float | int | color"
            android:valueTo="float | int | color"
            android:startOffset="int"
            android:repeatCount="int"
            android:repeatMode=["repeat" | "reverse"]
            android:valueType=["intType" | "floatType"]/>
    
        <animator
            android:duration="int"
            android:valueFrom="float | int | color"
            android:valueTo="float | int | color"
            android:startOffset="int"
            android:repeatCount="int"
            android:repeatMode=["repeat" | "reverse"]
            android:valueType=["intType" | "floatType"]/>
    
        <set>
            ...
        </set>
    </set>

    <set>对应AnimatorSet类,<objectAnimator>对应ObjectAnimator类,<animator>标签对应ValueAnimator类。

    在实际开发中建议使用代码方式来实现属性动画,因为很多时候属性是无法提前确定的。

    1、使用属性动画代码实现上边View动画的效果:

     //平移动画
    ObjectAnimator translate1 = ObjectAnimator.ofFloat(imageView, "translationX", 20, 100);
    translate1.setDuration(2000);
    ObjectAnimator translate2 = ObjectAnimator.ofFloat(imageView, "translationY", 20, 100);
    translate2.setDuration(2000);
    translate1.start();
    translate2.start();
    //伸缩动画
    ObjectAnimator scale1 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0.5f);
    scale1.setDuration(2000);
    scale1.setRepeatCount(ValueAnimator.INFINITE);
    scale1.setRepeatMode(ValueAnimator.REVERSE);
    ObjectAnimator scale2 = ObjectAnimator.ofFloat(imageView, "scaleY", 1f, 0.5f);
    scale2.setDuration(2000);
    scale2.setRepeatCount(ValueAnimator.INFINITE);
    scale2.setRepeatMode(ValueAnimator.REVERSE);
    scale1.start();
    scale2.start();
    //透明度动画
    ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView, "alpha", 1, 0, 1)
        .setDuration(2000);
    alpha.setRepeatCount(ValueAnimator.INFINITE);
    alpha.setRepeatMode(ValueAnimator.RESTART);
    alpha.start();
    //旋转动画
    ObjectAnimator rotate = ObjectAnimator.ofFloat(imageView, "rotation", 0, 360)
        .setDuration(2000);
    rotate.setRepeatCount(ValueAnimator.INFINITE);
    rotate.setRepeatMode(ValueAnimator.RESTART);
    rotate.start();

    2、对任意属性做动画

    举例改变Width代码,这里有两种方式,效果是一样的:

    方式一,包装原始对象,使用ObjectAnimator实现动画:

    //包装原始对象,为其提供set、get方法
    public static class ViewWrapper {
        private View mTarget;
    
        public ViewWrapper(View mTarget) {
            this.mTarget = mTarget;
        }
    
        public int getWidth() {
            return mTarget.getLayoutParams().width;
        }
    
        public void setWidth(int width) {
            mTarget.getLayoutParams().width = width;
            mTarget.requestLayout();
        }
    }
    //启动动画
    ViewWrapper wrapper = new ViewWrapper(imageView);
    ObjectAnimator animation = ObjectAnimator.ofInt(wrapper, "width", 10, 600).setDuration(3000);
    animation.setRepeatMode(ValueAnimator.REVERSE);
    animation.setRepeatCount(ValueAnimator.INFINITE);
    animation.setInterpolator(new DecelerateInterpolator());
    animation.start();

    方式二,使用ValueAnimator监听动画过程,实现属性变化

    ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    
        private IntEvaluator intEvaluator = new IntEvaluator();
    
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
        float fraction = valueAnimator.getAnimatedFraction();
        imageView.getLayoutParams().width = intEvaluator.evaluate(fraction, 10, 600);
        imageView.requestLayout();
        }
    });
    valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
    valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
    valueAnimator.setDuration(3000).start();

    3、属性动画集

     //平移动画
    ObjectAnimator translate1 = ObjectAnimator.ofFloat(imageView, "translationX", 20, 100);
    translate1.setDuration(2000);
    ObjectAnimator translate2 = ObjectAnimator.ofFloat(imageView, "translationY", 20, 100);
    translate2.setDuration(2000);
    //伸缩动画
    ObjectAnimator scale1 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0.5f);
    scale1.setDuration(2000);
    ObjectAnimator scale2 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0.5f);
    scale2.setDuration(2000);
    //透明度动画
    ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView, "alpha", 1, 0, 1)
        .setDuration(2000);
    //旋转动画
    ObjectAnimator rotate = ObjectAnimator.ofFloat(imageView, "rotation", 0, 360)
        .setDuration(2000);
    rotate.setRepeatCount(ValueAnimator.INFINITE);
    rotate.setRepeatMode(ValueAnimator.REVERSE);
    //    //平移动画集
    //    AnimatorSet translateSet = new AnimatorSet();
    //    translateSet.playTogether(translate1, translate2);
    //    translateSet.start();
    //    //伸缩动画集
    //    AnimatorSet scaleSet = new AnimatorSet();
    //    scaleSet.playTogether(scale1, scale2);
    //    scaleSet.start();
    //串行执行动画集
    AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.playSequentially(translate1, alpha, rotate);
    animatorSet.start();

    四、使用动画的注意事项

    1、OOM问题

    这个问题主要出现在帧动画中,当图片数量较多切图片较大时就容易出现OOM,这个实际开发中要注意,尽量表面使用帧动画。

    2、内存泄漏

    在属性动画中有一类无限循环的动画,这类动画需要在Activity退出时即使停止,否则将导致Activity无法释放从而造成内存泄漏,View动画不存在此问题。

    3、兼容性问题

    动画在3.0以下的系统上有兼容性问题,在某些特殊场景可能无法正常工作,因此要做好适配。

    4、View动画问题

    View动画是对View的影像做动画,并不是真正的改变View的状态,因此有时候会出现动画完成后View无法隐藏的现象,即setVisibility(View.GONE)失效了,这个时候只要调用View.clearAnimation()清除View动画即可。

    5、不要使用px

    在进行动画的过程中,要尽量使用dp,使用px会导致在不同的设备上有不同的效果。

    6、动画元素交互

    将View移动后,在Android3.0以前的系统上,不管是View动画还是属性动画,新位置无法触发单击事件。同时,老位置仍然可以出发单击事件。尽管View已经在视觉上不存在了,将View移回原位置后,原位置的单击事件继续生效。从3.0开始,属性动画的单击事件触发位置为移动后的位置,但是View动画仍然是在原位置。

    7、硬件加速

    使用动画的过程中,建议开启硬件加速(在manifest中Application、Activity级别上声明android:hardwareAccelerated="true"即可),这样会提高动画的流畅性。

    五、本文代码如下

    Android动画示例

  • 相关阅读:
    poj 3068 Bridge Across Islands
    XidianOJ 1086 Flappy v8
    XidianOJ 1036 分配宝藏
    XidianOJ 1090 爬树的V8
    XidianOJ 1088 AK后的V8
    XidianOJ 1062 Black King Bar
    XidianOJ 1091 看Dota视频的V8
    XidianOJ 1098 突击数论前的xry111
    XidianOJ 1019 自然数的秘密
    XidianOJ 1109 Too Naive
  • 原文地址:https://www.cnblogs.com/pear-lemon/p/6560395.html
Copyright © 2011-2022 走看看