帧动画的例子很多了。反正就是把图片一张一张的播放呗。
通常都需要建立一个xml文件来管理图片。比如这样:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="@drawable/d1" android:duration="100"/>
<item android:drawable="@drawable/d2" android:duration="100"/>
<item android:drawable="@drawable/d3" android:duration="100"/>
</animation-list>
然而,对于我这样的整理狂来说,看着这么一堆标签和drawable文件夹里的一堆图片不免心情烦躁。尤其是复杂的动画有几十帧的时候。
所以把他们都放在一张图片里使用就舒坦了。
(而且还有利于实现动画资源的热更新)
用的是类似这样的图:
使用这样的图片做帧动画也很简单,就是把原来拆好的多张图片,换成整个图片拉到应用里再拆成多份。
来,先上车再解释。以下是完整代码:
package com.boosj.view;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.boosj.boosjapp.R;
/**
* png序列图动画类
*/
public class pngAnimView extends FrameLayout{
private ImageView animImage;
//实现动画的类
private AnimationDrawable animDrawable;
public pngAnimView(Context context) {
super(context);
init(context);
}
public pngAnimView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
LayoutInflater.from(context).inflate(R.layout.pnganimview_l, this);
animImage=(ImageView) findViewById(R.id.animView);
animDrawable=new AnimationDrawable();
}
/*
* _f 动画的帧数
* _res 资源图编号
* _isH 资源图序列行列形式,true=横排
*/
public void setInfo(int _f,int _res,boolean isH) {//参数为帧数和资源图编号
try {
Resources res = getResources();
//获取资源图的bitmap
BitmapDrawable bmpDraw = (BitmapDrawable) res.getDrawable(_res);
Bitmap bmp = bmpDraw.getBitmap();
int _w=bmp.getWidth();
int _h=bmp.getHeight();
int _ew = _w / _f;
int _eh = _h / _f;
for (int frame = 0; frame < _f; frame++) {
//分解资源图
Bitmap bitmap;
if(isH) {
bitmap = Bitmap.createBitmap(bmp, frame * _ew, 0, _ew, _h);
}else{
bitmap = Bitmap.createBitmap(bmp, 0, frame * _eh, _w, _eh);
}
//填充每帧图片
animDrawable.addFrame(new BitmapDrawable(null, bitmap), 100);
}
//将动画设置给ImageView
animImage.setImageDrawable(animDrawable);
//设置循环播放
animDrawable.setOneShot(false);
}catch (Exception e){
}
}
public void startAnim(){
try {
animDrawable.start();
}catch (Exception e){
}
}
public void stopAnim(){
try {
animDrawable.stop();
}catch (Exception e){
}
}
private void tryRecycleAnimationDrawable(AnimationDrawable animationDrawables) {
if (animationDrawables != null) {
animationDrawables.stop();
for (int i = 0; i < animationDrawables.getNumberOfFrames(); i++) {
Drawable frame = animationDrawables.getFrame(i);
if (frame instanceof BitmapDrawable) {
((BitmapDrawable) frame).getBitmap().recycle();
}
frame.setCallback(null);
}
animationDrawables.setCallback(null);
}
}
public void releaseBitmap(boolean force){
tryRecycleAnimationDrawable(animDrawable);
if(force){
System.gc();
}
}
}
一点小说明:
那么可以看到,最主要就是setInfo()这个方法了。
根据帧数_f,将图片的bitmap分成_f个等分的尺寸:
int _w=bmp.getWidth();
int _h=bmp.getHeight();
int _ew = _w / _f;
int _eh = _h / _f;
然后根据每帧的尺寸获得每帧的对应bitmap图:
//分解资源图
Bitmap bitmap;
if(isH) {
bitmap = Bitmap.createBitmap(bmp, frame * _ew, 0, _ew, _h);
}else{
bitmap = Bitmap.createBitmap(bmp, 0, frame * _eh, _w, _eh);
}
这里我选用了两种排列,横排和竖排。当然也可以做成多行或多列。分割方法稍作改动就好了。
最后再将每份小图添加到帧动画里AnimationDrawable里。
//填充每帧图片
animDrawable.addFrame(new BitmapDrawable(null, bitmap), 100);
计算很简单,使用很方便。
需要注意的是使用完别忘了使用tryRecycleAnimationDrawable函数释放所有的帧。不然分分钟就OOM了。