您的位置:首页 > 其它

逐帧动画详解

2016-08-30 20:36 351 查看
概述

逐帧动画(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]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  逐帧动画