日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

android 自定义帧动画,Android 自定义方式实现帧动画效果

發(fā)布時間:2023/12/15 Android 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 自定义帧动画,Android 自定义方式实现帧动画效果 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

首先說下為啥要通過自定義處理的方式去實現(xiàn)Android的幀動畫效果,因為通過系統(tǒng)原生支持的xml和java代碼這兩種方式實現(xiàn),在播放的圖片量很多時,會出現(xiàn)內(nèi)存溢出,此現(xiàn)象也是在做項目當(dāng)中有遇到,出現(xiàn)的情景:loading視圖,由于項目中的加載視圖采用的是播放一組連續(xù)圖片來實現(xiàn)動畫效果。殊不知這樣做是有隱患的,那就是造成了大名鼎鼎的OOM。經(jīng)過幾番折騰和各種嘗試,最終還是決定放棄原來幀動畫實現(xiàn)方式,另辟蹊徑。

方式一:

1.定義類XAnimationDrawable,在內(nèi)部采用定時器給ImageView設(shè)置圖片。

2.使用步驟:

1)實例XAnimationDrawable和ImageView

XAnimationDrawable frameAnimation = new XAnimationDrawable();

ImageView iv = (ImageView)findViewById(R.id.iv_animation);

2)準(zhǔn)備圖片id資源,以下提供了兩種方式

//通過代碼添加圖片id資源

List ids = new ArrayList();

ids.add(R.drawable.footer_loading_710000);

ids.add(R.drawable.footer_loading_710001);

......

ids.add(R.drawable.footer_loading_710015);

ids.add(R.drawable.footer_loading_710016);

//通過xml的定義,footer_loading_list.xml

android:oneshot="false">

android:drawable="@drawable/footer_loading_710000"

android:duration="60" />

android:drawable="@drawable/footer_loading_710001"

android:duration="60" />

......

android:drawable="@drawable/footer_loading_710008"

android:duration="60" />

android:drawable="@drawable/footer_loading_710009"

android:duration="60" />

3)設(shè)置播放的圖片資源

//通過代碼添加圖片id資源對應(yīng)的播放動畫方式

frameAnimation.setAnimation(iv, ids);

//通過xml定義圖片id資源列表對應(yīng)的播放動畫方式

frameAnimation.setAnimation(context, R.drawable.footer_loading_list, iv);

4)開始動畫

frameAnimation.start(true, 80);

XAnimationDrawable.java

public class XAnimationDrawable {

private static final int MSG_START = 0xf1;

private static final int MSG_STOP = 0xf2;

private static final int STATE_STOP = 0xf3;

private static final int STATE_RUNNING = 0xf4;

//運行狀態(tài)

private int mState = STATE_RUNNING;

//顯示圖片的View

private ImageView mImageView = null;

//圖片資源的ID列表

private List mResourceIdList = null;

//定時任務(wù)器

private Timer mTimer = null;

//定時任務(wù)

private AnimTimerTask mTimeTask = null;

//記錄播放位置

private int mFrameIndex = 0;

//播放形式

private boolean isLooping = false;

public XAnimationDrawable() {

mTimer = new Timer();

}

/**

* 設(shè)置動畫播放資源

*/

public void setAnimation(ImageView imageview, List resourceIdList){

mImageView = imageview;

mResourceIdList = new ArrayList();

mResourceIdList.clear();

mResourceIdList.addAll(resourceIdList);

}

/**

* 設(shè)置動畫播放資源

*/

public void setAnimation(Context context, int resourceId, ImageView imageview){

this.mImageView = imageview;

mResourceIdList = new ArrayList();

mResourceIdList.clear();

loadFromXml(context, resourceId, new OnParseListener() {

@Override

public void onParse(List res) {

mResourceIdList.addAll(res);

}

});

}

/**

* 解析xml

*

* @param context

* @param resourceId 資源id

*/

private void loadFromXml(final Context context, final int resourceId,

final OnParseListener onParseListener) {

if (context == null) {

return;

}

final List res = new ArrayList();

XmlResourceParser parser = context.getResources().getXml(resourceId);

try {

int eventType = parser.getEventType();

while (eventType != XmlPullParser.END_DOCUMENT) {

if (eventType == XmlPullParser.START_DOCUMENT) {

} else if (eventType == XmlPullParser.START_TAG) {

if (parser.getName().equals("item")) {

for (int i = 0; i < parser.getAttributeCount(); i++) {

if (parser.getAttributeName(i).equals("drawable")) {

int resId = Integer.parseInt(parser.getAttributeValue(i).substring(1));

res.add(resId);

}

}

}

} else if (eventType == XmlPullParser.END_TAG) {

} else if (eventType == XmlPullParser.TEXT) {

}

eventType = parser.next();

}

} catch (IOException e) {

// TODO: handle exception

e.printStackTrace();

} catch (XmlPullParserException e2) {

// TODO: handle exception

e2.printStackTrace();

} finally {

parser.close();

}

if (onParseListener != null) {

onParseListener.onParse(res);

}

}

/**

* 開始播放動畫

* @param loop 是否循環(huán)播放

* @param duration 動畫播放時間間隔

*/

public void start(boolean loop, int duration){

stop();

if (mResourceIdList == null || mResourceIdList.size() == 0) {

return;

}

if (mTimer == null) {

mTimer = new Timer();

}

isLooping = loop;

mFrameIndex = 0;

mState = STATE_RUNNING;

mTimeTask = new AnimTimerTask( );

mTimer.schedule(mTimeTask, 0, duration);

}

/**

* 停止動畫播放

*/

public void stop(){

if (mTimer != null) {

mTimer.purge();

mTimer.cancel();

mTimer = null;

}

if (mTimeTask != null) {

mFrameIndex = 0;

mState = STATE_STOP;

mTimeTask.cancel();

mTimeTask = null;

}

//移除Handler消息

if (AnimHandler != null) {

AnimHandler.removeMessages(MSG_START);

AnimHandler.removeMessages(MSG_STOP);

AnimHandler.removeCallbacksAndMessages(null);

}

}

/**

* 定時器任務(wù)

*/

class AnimTimerTask extends TimerTask {

@Override

public void run() {

if (mFrameIndex < 0 || mState == STATE_STOP) {

return;

}

if (mFrameIndex < mResourceIdList.size()) {

Message msg = AnimHandler.obtainMessage(MSG_START, 0, 0, null);

msg.sendToTarget();

} else {

mFrameIndex = 0;

if(!isLooping){

Message msg = AnimHandler.obtainMessage(MSG_STOP, 0, 0, null);

msg.sendToTarget();

}

}

}

}

/**

* Handler

*/

private Handler AnimHandler = new Handler(){

public void handleMessage(Message msg) {

switch (msg.what) {

case MSG_START:{

if(mFrameIndex >= 0 && mFrameIndex < mResourceIdList.size() && mState == STATE_RUNNING){

mImageView.setImageResource(mResourceIdList.get(mFrameIndex));

mFrameIndex++;

}

}

break;

case MSG_STOP:{

if (mTimeTask != null) {

mFrameIndex = 0;

mTimer.purge();

mTimeTask.cancel();

mState = STATE_STOP;

mTimeTask = null;

if (isLooping) {

mImageView.setImageResource(0);

}

}

}

break;

default:

break;

}

}

};

public interface OnParseListener {

void onParse(List res);

}

}

方式二:

1.定義類XFrameAnimation,繼承自Drawable類,同時實現(xiàn)Animatable接口。

2.XFrameAnimation內(nèi)部通過ValueAnimator(動畫的數(shù)值發(fā)生器)來有序的產(chǎn)生圖片資源的resId,然后在自身的draw方法中將resId對應(yīng)的資源繪制到Canvas上。傳入的是一個圖片資源數(shù)組,所以呈現(xiàn)出來的就是一個幀動畫的效果。

3.使用

// 圖片資源Id數(shù)組

int[] RES_IDS = new int[]{

R.drawable.loading_1840000,

R.drawable.loading_1840001,

......

};

// 構(gòu)建播放圖片的XFrameAnimation

XFrameAnimation loadingDrawable = new XFrameAnimation(600, RES_IDS, getContext().getResources());

ImageView ivLoadingImage = (ImageView) findViewById(R.id.iv_loading_image);

ivLoadingImage.setImageDrawable(loadingDrawable);

4.代碼(參考自網(wǎng)上一位大神分享的,具體原鏈接暫時找不著了,這個代碼是之前寫的)

public class XFrameAnimation extends Drawable implements Animatable {

private static final long DEFAULT_DURATION = 500;

private long duration = DEFAULT_DURATION;

private final Paint mPaint;

private final int[] RES_IDS;

private int resIndex;

private final Resources mResources;

private ValueAnimator mAnimator;

private ValueAnimator.AnimatorUpdateListener mAnimUpdateListener;

//取第一幀,用于獲取圖片寬高

private Drawable mFirstDrawable;

public XFrameAnimation(int[] RES_IDS, Resources resources) {

this(DEFAULT_DURATION, RES_IDS, resources);

}

public XFrameAnimation(long duration, int[] RES_IDS, Resources resources) {

this.duration = duration;

this.RES_IDS = RES_IDS;

this.mResources = resources;

mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

mPaint.setFilterBitmap(true);

mPaint.setDither(true);

if (this.RES_IDS == null || this.RES_IDS.length <= 0) {

throw new RuntimeException(" XFrameAnimation RES_IDS can not null or empty !!!");

}

mFirstDrawable = resources.getDrawable(this.RES_IDS[0]);

createAnimator();

}

/**

* 初始化動畫

*/

private void createAnimator() {

mAnimator = ValueAnimator.ofInt(RES_IDS.length - 1);

mAnimator.setInterpolator(new LinearInterpolator());

mAnimator.setRepeatCount(ValueAnimator.INFINITE);

mAnimator.setRepeatMode(ValueAnimator.RESTART);

mAnimator.setDuration(duration);

mAnimUpdateListener = new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

invalidate(((int) animation.getAnimatedValue()));

}

};

}

/**

* 重繪

*

* @param index 幀索引

*/

public void invalidate(int index) {

this.resIndex = index;

invalidateSelf();

}

/**

* 獲取動畫幀數(shù)

*

* @return 幀數(shù)量

*/

public int getFrameCount(){

return RES_IDS.length;

}

@Override

public void draw(Canvas canvas) {

if (mResources != null) {

BitmapDrawable drawable = (BitmapDrawable) mResources.getDrawable(RES_IDS[resIndex % RES_IDS.length]);

Bitmap bitmap = drawable.getBitmap();

canvas.drawBitmap(bitmap, 0, 0, mPaint);

}

}

@Override

public void setAlpha(int alpha) {

}

@Override

public void setColorFilter(ColorFilter colorFilter) {

mPaint.setColorFilter(colorFilter);

}

@Override

public int getOpacity() {

return PixelFormat.OPAQUE;

}

@Override

public void start() {

// If the animators has not ended, do nothing.

if (mAnimator.isStarted()) {

return;

}

startAnimator();

invalidateSelf();

}

/**

* 開始執(zhí)行動畫

*/

private void startAnimator() {

if (mAnimator != null) {

mAnimator.addUpdateListener(mAnimUpdateListener);

mAnimator.start();

}

}

@Override

public void stop() {

if (mAnimator != null && mAnimator.isStarted()) {

mAnimator.removeAllUpdateListeners();

mAnimator.end();

}

}

@Override

public boolean isRunning() {

return mAnimator.isRunning();

}

@Override

public int getIntrinsicWidth() {

return mFirstDrawable.getIntrinsicWidth();

}

@Override

public int getIntrinsicHeight() {

return mFirstDrawable.getIntrinsicHeight();

}

}

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的android 自定义帧动画,Android 自定义方式实现帧动画效果的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。