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动画示例

  • 相关阅读:
    HDU 6043
    HDU 6033
    HDU 6041
    HDU 6050
    HDU 6053
    HDU 6055
    HDU 6045
    HDU 6044
    HDU 6040
    ZUFE 1035 字符宽度编码(字符串)
  • 原文地址:https://www.cnblogs.com/pear-lemon/p/6560395.html
Copyright © 2011-2022 走看看