逐帧动画详解

概述
逐帧动画(Frame Animation),是通过将一系列图片按照一定的顺序展示实现的动画。同是视图动画(View Animation),在使用时比补间动画(Tween animation)要简单很多。

一、逐帧动画的使用
(1).使用xml文件创建
节点介绍:
<animation-list>:必须作为根元素,可以包含一个或多个<item>元素。
<item>:代表一帧动画。
属性介绍:
android:oneshot:若等于true,动画只执行一次;否则一直循环。
android:drawable:当前帧所对应的图片资源。
android:duration:当前帧持续的时长,单位毫秒。

示例代码:
/res/drawable目录下添加如下5张图片。

在/res/drawable目录下添加wifi_anim.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/card_icon_wifi_0" android:duration="500" />
    <item android:drawable="@drawable/card_icon_wifi_1" android:duration="500" />
    <item android:drawable="@drawable/card_icon_wifi_2" android:duration="500" />
    <item android:drawable="@drawable/card_icon_wifi_3" android:duration="500" />
    <item android:drawable="@drawable/card_icon_wifi_4" android:duration="500" />
</animation-list>
将上面创建的动画应用到布局的View中。
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/wifi_anim"/>
在java代码中启动动画。
// 获取AnimationDrawable对象
AnimationDrawable animation = (AnimationDrawable) imageView.getBackground();
// 启动动画
animation.start();

(2).使用java代码创建
示例代码:
AnimationDrawable animation = new AnimationDrawable();
for (int i = 0; i < 5; i++) {
  int id = getResources().getIdentifier("card_icon_wifi_" + i, "drawable", getPackageName());
  Drawable drawable = getResources().getDrawable(id);
  // 调用addFrame()方法依次添加drawable对象
  animation.addFrame(drawable, 500);
}
// 添加到View中
imageView.setBackgroundDrawable(anim);
// 启动动画
animation.start();

注意:在Activity的onCreate()方法中,由于Window对象还未初始化完成,此时调用animation.start(),动画不会执行。若需要在Activity启动时就显示动画,可以在onWindowFocusChanged(boolean hasFocus)方法中启动。

二、逐帧动画的分析
逐帧动画是通过 AnimationDrawable类来实现。在AnimationDrawable类中,定义了一个AnimationState类型的成员变量mAnimationState,用来存储一系列的drawable对象。
public class AnimationDrawable extends DrawableContainer implements Runnable, Animatable {
    // ...
    private AnimationState mAnimationState;
    // ...
}

AnimationState继承自DrawableContainerState类。AnimationState类自己定义了成员变量mDurations和mOneShot,分别存储每一帧的时长和动画是否需要循环。而在其父类中有一个Drawable类型数组mDrawables,用于存储每一帧drawable对象。
private final static class AnimationState extends DrawableContainerState {
    // ...
    private int[] mDurations;
    private boolean mOneShot = false;
    // ...

    public void addFrame(Drawable dr, int dur) {
        // ...
        int pos = super.addChild(dr);
        mDurations[pos] = dur;
	// ...
    }
    // ...
}

public abstract static class DrawableContainerState extends ConstantState {
    // ...
    Drawable[] mDrawables;
    // ...

    public final int addChild(Drawable dr) {
        // ...
        mDrawables[pos] = dr;
	// ...
    }
}

当调用addFrame()方法时,动画的每一帧被依次添加到成员变量mAnimationState中。
public void addFrame(@NonNull Drawable frame, int duration) {
    mAnimationState.addFrame(frame, duration);
    if (!mRunning) {
        setFrame(0, true, false);
    }
}

最后,调用start()方法启动动画。方法内部调用了setFrame()方法,在setFrame()中调用selectDrawable(),传入当前帧的索引,并在方法最后调用invalidateSelf()重写绘制。
public void start() {
    mAnimating = true;

    if (!isRunning()) {
        // Start from 0th frame.
        setFrame(0, false, mAnimationState.getChildCount() > 1
                || !mAnimationState.mOneShot);
    }
}

private void setFrame(int frame, boolean unschedule, boolean animate) {
    if (frame >= mAnimationState.getChildCount()) {
        return;
    }
    mAnimating = animate;
    mCurFrame = frame;
    selectDrawable(frame);
    if (unschedule || animate) {
        unscheduleSelf(this);
    }
    if (animate) {
        // Unscheduling may have clobbered these values; restore them
        mCurFrame = frame;
        mRunning = true;
        scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]);
    }
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值