美文网首页
Android几种动画的总结(逐帧动画、补间动画)

Android几种动画的总结(逐帧动画、补间动画)

作者: 锐_nmpoi | 来源:发表于2017-04-12 10:25 被阅读193次

    逐帧动画

    逐帧动画也叫 Drawable Animation,是最简单最直观的动画效果。

    在Android 中实现逐帧动画就是由设计师给出一系列状态不断变化的图片,开发者就指定这些图片显示的持续时间,然后顺序开始播放这些图片,就形成了动画了。

    使用逐帧动画 既可以使用XML的方法实现,也可以使用代码来实现。

    XML

    首先把资源文件(每一帧的图片)放在 res/drawable 下。 如图:

    然后在这里 新建一个XML文件。 在这个文件中使用的 <animation-list>标签来定义动画。使用<item>标签来定义动画的每一帧,并在每一个<item>中指定自己的属性,例如 持续时间 android:duration="300" 、 这一帧使用的图片 android:drawable="@drawable/z_1_die_01" 。

    frme_animation.xml

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    
        <item
            android:drawable="@drawable/z_1_die_01"
            android:duration="300"/>
        <item
            android:drawable="@drawable/z_1_die_02"
            android:duration="300"/>
        <item
            android:drawable="@drawable/z_1_die_03"
            android:duration="300"/>
        <item
            android:drawable="@drawable/z_1_die_04"
            android:duration="300"/>
        <item
            android:drawable="@drawable/z_1_die_05"
            android:duration="300"/>
    
    </animation-list>
    

    android:oneshot 来控制动画是否循环播放, false 表示 循环播放 , true 表示 不循环播放 。

    在控件的布局中给控件使用这个 drawable 文件

    <ImageView
    android:id="@+id/iv_frame_xml"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/frme_animation"/>
    

    定义好了这个动画,为了让动画播放,就要使用代码让他开始播放,代码如下:

    //xml
    ImageView ivFrameXml = (ImageView) findViewById(R.id.iv_frame_xml);
    AnimationDrawable background = (AnimationDrawable)ivFrameXml.getDrawable();
    background.start();
    

    代码方式

    代码的方式更加简单,新建一个 AnimationDrawable ,并为他增加每一帧的图片和持续时间就可以了。

    //code
    ImageView ivFrameCode = (ImageView) findViewById(R.id.iv_frame_code);
    AnimationDrawable animationDrawable = new AnimationDrawable();
    for (int i = 1; i <= 5; i++) {
        int id = getResources().getIdentifier("z_1_die_0" + i, "drawable", getPackageName());
        Drawable drawable = getResources().getDrawable(id);
        animationDrawable.addFrame(drawable,300);
    }
    ivFrameCode.setImageDrawable(animationDrawable);
        //循环播放
    animationDrawable.setOneShot(false);
        //开始播放
    animationDrawable.start();
    

    效果如图所示:

    补间动画

    补间动画无须再知道动画过程中的每一帧了,只需要定义动画的开始和结束,并且指定变化的时间和方式就可以了,他会自动补全中间的过程。Android会通过所给出的开始值与结束值,再根据中间变化的规律,最后计算出每一帧图片显示的效果,最后直接显示出来。

    主要包括这四种基本效果:透明度变化 Alpha 、缩放变化 Scale 、 位移变化 Translate 、旋转变化 Rotate 。这四种效果可以动态组合,从而实现复杂的动画。

    插值器 Interpolator

    补间动画能够自己补充中间的内容,其实靠的就是这个。

    Interpolator 会根据类型不同,选择不同的算法计算出补间动画所需要动态插入的密度和位置,Interpolator 负责控制动画的变化速度,他可以 匀速、加速、减速、抛物线等多种变化。

    public interface Interpolator extends TimeInterpolator {
        // A new interface, TimeInterpolator, was introduced for the new android.animation
        // package. This older Interpolator interface extends TimeInterpolator so that users of
        // the new Animator-based animations can use either the old Interpolator implementations or
        // new classes that implement TimeInterpolator directly.
    }
    
    public interface TimeInterpolator {
    
        /**
         * Maps a value representing the elapsed fraction of an animation to a value that represents
         * the interpolated fraction. This interpolated value is then multiplied by the change in
         * value of an animation to derive the animated value at the current elapsed animation time.
         *
         * @param input A value between 0 and 1.0 indicating our current point
         *        in the animation where 0 represents the start and 1.0 represents
         *        the end
         * @return The interpolation value. This value can be more than 1.0 for
         *         interpolators which overshoot their targets, or less than 0 for
         *         interpolators that undershoot their targets.
         */
        float getInterpolation(float input);
    }
    

    由上面的代码可以清楚的看到一点,Interpolator 只是继承于 TimeInterpolator ,里面只是一个空实现而已。而在 TimeInterpolator 下,也只有 float getInterpolation(float input); 一个方法。input 是一个 0.0 ~ 1.0 的值 , 经过自定义的方法 ,那么只要返回适当的值,那么就能实现各种的效果。

    例如下面是系统实现的先加速后减速的Interpolator。

    AccelerateDecelerateInterpolator

     public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
    

    当然Android SDK 中已经实现了几个 Interpolator 让开发者直接使用。

    下面继续介绍动画,补间动画和逐帧动画一样,既能使用XML实现也能使用Code实现。

    XML的文件应放置在 res/anim 目录上。

    透明度变化 Alpha

    XML

    anim_tween_alpha.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    >
    
    <alpha
        android:repeatMode="reverse"
        android:repeatCount="-1"
        android:duration="1000"
        android:fromAlpha="0"
        android:toAlpha="1" />
    
    </set>
    

    android:interpolator 用来指定插值器

    android:repeatMode 重复的模式

    android:repeatCount="-1" 重复的次数。 -1 为无限循环。

    XML写完了,就要在代码中使用他了。

    ImageView ivTweenXml = (ImageView) findViewById(R.id.iv_tween_xml);
    AnimationSet alphaSet  = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_alpha);
    ivTweenXml.startAnimation(alphaSet);
    

    Code

    ImageView ivTweenCode = (ImageView) findViewById(R.id.iv_tween_code);
    AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
    alphaAnimation.setDuration(1000);
    alphaAnimation.setRepeatMode(Animation.REVERSE);
    alphaAnimation.setRepeatCount(-1);
    ivTweenCode.startAnimation(alphaAnimation);
    

    上面都实现了透明度从0到1.

    缩放变化 Scale

    XML

    anim_tween_scale.xml

    <set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator">
    
        <scale
            android:duration="1000"
            android:fromXScale="0.2"
            android:fromYScale="0.2"
            android:toXScale="1"
            android:toYScale="1"
            android:pivotX="50%"
            android:pivotY="50%"
            android:repeatCount="-1"
            android:repeatMode="reverse"
             />
    
    </set>
    
      ImageView ivScaleXml = (ImageView) findViewById(R.id.iv_scale_xml);
      AnimationSet scaleSet  = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_scale);
      ivScaleXml.startAnimation(scaleSet);
    

    pivotX 中心点
    直接写数字代表 控件本身的坐标系中的x的值
    数字后面加了 % 例如 :50% ,代表 在本身的坐标系中的 x轴长度的50%

    Code

    ImageView ivScaleCode = (ImageView) findViewById(R.id.iv_scale_code);
    ScaleAnimation scaleAnimation = new ScaleAnimation(0.2f, 1, 0.2f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    scaleAnimation.setDuration(1000);
    scaleAnimation.setRepeatMode(Animation.REVERSE);
    scaleAnimation.setRepeatCount(-1);
    ivScaleCode.startAnimation(scaleAnimation);
    

    位移变化 Translate

    XML

    anim_tween_translate.xml

    <set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator">
    
        <translate
            android:duration="1000"
            android:fromXDelta="0"
            android:fromYDelta="0"
            android:toXDelta="100"
            android:toYDelta="0"
            android:repeatCount="-1"
            android:repeatMode="reverse"
             />
    
    </set>
    
     ImageView ivTranslateXml = (ImageView) findViewById(R.id.iv_translate_xml);
    AnimationSet translateSet  = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_translate);
    ivTranslateXml.startAnimation(translateSet);
    

    Code

      ImageView ivTranslateCode = (ImageView) findViewById(R.id.iv_translate_code);
      TranslateAnimation translateAnimation = new TranslateAnimation( 0,100,0,0);
      translateAnimation.setDuration(1000);
      translateAnimation.setRepeatMode(Animation.REVERSE);
      translateAnimation.setRepeatCount(-1);
      ivTranslateCode.startAnimation(translateAnimation);
    

    旋转变化 Rotate

    XML

    anim_tween_rotate.xml

    <set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator">
    
    <rotate
        android:duration="1000"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:toXScale="1"
        android:toYScale="1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="-1"
        android:repeatMode="reverse"
         />
    
    </set>
    
    ImageView ivRotateXml = (ImageView) findViewById(R.id.iv_rotate_xml);
    AnimationSet rotateSet  = (AnimationSet) AnimationUtils.loadAnimati(TweenActivity.this,R.anim.anim_tween_rotate);
    ivRotateXml.startAnimation(rotateSet);
    

    Code

    ImageView ivRotateCode = (ImageView) findViewById(R.id.iv_rotate_code);
    RotateAnimation rotateAnimation = new RotateAnimation( 0,360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    rotateAnimation.setDuration(1000);
    rotateAnimation.setRepeatMode(Animation.REVERSE);
    rotateAnimation.setRepeatCount(-1);
    ivRotateCode.startAnimation(rotateAnimation);
    

    组合起来

    上面显示的就是每一种效果各自实现的方法,现在我们可以让这些效果组合起来。

    xml

    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        >
    
        <alpha
            android:duration="1000"
            android:fromAlpha="0"
            android:repeatCount="-1"
            android:repeatMode="reverse"
            android:toAlpha="1" />
    
        <rotate
            android:duration="1000"
            android:fromDegrees="0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:repeatCount="-1"
            android:repeatMode="reverse"
            android:toDegrees="360"
            android:toXScale="1"
            android:toYScale="1" />
    
    
        <scale
            android:duration="1000"
            android:fromXScale="0.2"
            android:fromYScale="0.2"
            android:pivotX="50%"
            android:pivotY="50%"
            android:repeatCount="-1"
            android:repeatMode="reverse"
            android:toXScale="1"
            android:toYScale="1" />
    
        <translate
            android:duration="1000"
            android:fromXDelta="0"
            android:fromYDelta="0"
            android:repeatCount="-1"
            android:repeatMode="reverse"
            android:toXDelta="100"
            android:toYDelta="0" />
    </set>
    
    ImageView ivTogetherXml = (ImageView) findViewById(R.id.iv_together_xml);
    AnimationSet togetherSet  = (AnimationSet) AnimationUtils.loadAnimation(TweenActivity.this,R.anim.anim_tween_together);
    ivTogetherXml.startAnimation(togetherSet);
    

    Code

    ImageView ivTogetherCode = (ImageView) findViewById(R.id.iv_together_code);
    AnimationSet animationSet = new AnimationSet(false);
    animationSet.addAnimation(alphaAnimation);
    animationSet.addAnimation(rotateAnimation);
    animationSet.addAnimation(translateAnimation);
    animationSet.addAnimation(scaleAnimation);
    ivTogetherCode.startAnimation(animationSet);
    

    效果如图所示:

    监听

    播放动画效果的时候我们可以做到对动画开始、结束、重复的监听。

    alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                //动画开始时调用
            }
    
            @Override
            public void onAnimationEnd(Animation animation) {
                //动画结束时调用
            }
    
            @Override
            public void onAnimationRepeat(Animation animation) {
                //动画重复时调用
            }
        });
    

    只要在对应的位置添加自己想要的效果,那么就可以实现了。

    AccelerateInterpolator 加速,开始时慢中间加速

    几种自带的动画插入器

    DecelerateInterpolator 减速,开始时快然后减速

    AccelerateDecelerateInterolator 先加速后减速,开始结束时慢,中间加速

    AnticipateInterpolator 反向,先向相反方向改变一段再加速播放

    AnticipateOvershootInterpolator 反向加超越,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值

    BounceInterpolator 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100

    CycleIinterpolator 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2* mCycles* Math.PI* input)

    LinearInterpolator 线性,线性均匀改变

    OvershootInterpolator超越,最后超出目的值然后缓慢改变到目的值

    相关文章

      网友评论

          本文标题:Android几种动画的总结(逐帧动画、补间动画)

          本文链接:https://www.haomeiwen.com/subject/ymopattx.html