逐帧动画详解
概述
逐幀動畫(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中。
<ImageViewandroid: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 themmCurFrame = frame;mRunning = true;scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]);} }
逐幀動畫(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中。
<ImageViewandroid: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 themmCurFrame = frame;mRunning = true;scheduleSelf(this, SystemClock.uptimeMillis() + mAnimationState.mDurations[frame]);} }
總結
- 上一篇: 希沃白板5和html5,希沃白板5官方版
- 下一篇: 如何在本地电脑搭建asp(php)网站环