【www.bbyears.com--php框架模板】
帧动画
一开始我的想法是直接用帧动画来做,可是我太天真了,当帧数放到 50 几张的时候,已经在有些机器上奔溃了!所以这个方案否决!
GIF动图
虽然可以显示,但是已经卡的我,已经不想看了,直接放弃
视频
在这里,我突然想到我可以直接把他做成一个小视频啊,而且可以极限压缩视频。最终,视频大小被压缩到 500K 左右。此时已经基本可以满足需求了,但是我们有好多类似的动画,要求在每个动画切换的时候要有衔接感,不能有突兀的感觉,所有在这里视频就不能很好的完成任务了,所有再次放弃,已经泪牛满面了!!!!
SurfaceView + BitmapRegionDecoder +缓存
首先回答一下:为什么会想到这个解决方案?
首先在做帧动画的时候,大约每帧之间的时间差值是 40ms 可以说速度非常快了,在如此快速的图片切换上,自然而然的想到来了使用SurfaceView。
现在再来说说为什么想到要使用这个类 BitmapRegionDecoder .这个也是从我司游戏开发人员那儿得到的经验?他们在做游戏的时候,游戏中的切图都是放在一张大图上的,然后在根据对应的 xml,json 文件,获取相应的图片,接着再来切图。对此,我想能不能把所有的动图都放到同一张的图片上呢,之后在根据对应的描述文件,裁剪出我想要的图片呢!所以就用到了 BitmapRegionDecoder. 它的作用是:于显示图片的某一块矩形区域!之后,我在找设计人员商量一一下,把图片在尽量的压缩。之后从美工那儿获取的信息是这样的:
json格式的描述文件:
{"frames": [
{
"filename": "kidbot-正常闭眼0000",
"frame": {"x":0,"y":0,"w":360,"h":300},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":360,"h":300},
"sourceSize": {"w":360,"h":300}
}
.....
}
png图片:
接下来就好做了,解析 json 格式的文件,裁剪图片。
最后说一下为什么使用缓存,其实很简单,因为切换的频率实在太高了,没有必要每次都从图片中裁剪,这里就把裁剪出来的 bitmap 缓存起来在用。从而介绍内存开销!
最后给出代码:
public class AnimView extends SurfaceView implements SurfaceHolder.Callback { private BitmapRegionDecoder bitmapRegionDecoder; private SurfaceHolder mHolder; private boolean isrunning = true; private AnimThread thread; private Paint mPaint; private int WIDTH = 0; private int HEIGHT = 0; private int state = -1; private boolean isstart = false; private boolean isblinkfirst = false; private int rate = 40; private int index = 0; private Matrix matrix; private Random rand; private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { isblinkfirst = true; }; }; private SparseArray> weakBitmaps; private SparseArray > cweakBitmaps; private BitmapFactory.Options options; public AnimView(Context context) { super(context); init(); } public AnimView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public AnimView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } @SuppressLint("NewApi") private void init() { weakBitmaps = new SparseArray >(); cweakBitmaps = new SparseArray >(); mHolder = getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); setState(FaceBean.BLINK); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); matrix = new Matrix(); float[] values = { -1f, 0.0f, 0.0f, 0.0f, 1f, 0.0f, 0.0f, 0.0f, 1.0f }; matrix.setValues(values); WindowManager manger = (WindowManager) getContext().getSystemService( Context.WINDOW_SERVICE); DisplayMetrics displayMetrics = new DisplayMetrics(); manger.getDefaultDisplay().getMetrics(displayMetrics); WIDTH = displayMetrics.widthPixels / 2; HEIGHT = displayMetrics.heightPixels / 2; rand = new Random(); options = new Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; } @Override public void surfaceCreated(SurfaceHolder holder) { handler.sendEmptyMessageDelayed(0, 1000 * (4 + rand.nextInt(4))); thread = new AnimThread(); thread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (thread != null) { thread.stopThread(); } } public class AnimThread extends Thread { @Override public void run() { super.run(); SurfaceHolder holder = mHolder; while (isrunning) { Canvas canvas = holder.lockCanvas(); if (canvas == null) continue; synchronized (AnimThread.class) { AnimBean.Frames frames; switch (state) { case FaceBean.BLINK: frames = KidbotRobotApplication.animBlink.getFrames() .get(index); if (frames.getFrame().getW() <= 0) { } else { Rect rect = new Rect(frames.getFrame().getX(), frames.getFrame().getY(), frames.getFrame() .getX() + frames.getSourceSize().getW(), frames.getFrame().getY() + frames.getSourceSize().getH()); WeakReference weakBitmap = weakBitmaps .get(index); Bitmap map = null; if (weakBitmap == null) { map = bitmapRegionDecoder.decodeRegion(rect, options); weakBitmaps.put(index, new WeakReference (map)); } else { map=weakBitmap.get(); if (map == null) { map = bitmapRegionDecoder.decodeRegion( rect, options); weakBitmaps.put(index, new WeakReference (map)); } } if (map == null) { holder.unlockCanvasAndPost(canvas); continue; } mPaint.setXfermode(new PorterDuffXfermode( Mode.CLEAR)); canvas.drawPaint(mPaint); mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); canvas.drawBitmap(map, (int) (WIDTH - (map.getWidth() * 1) - 150), (int) (HEIGHT - (map.getHeight() / 2)), mPaint); canvas.drawBitmap(map, (int) (WIDTH + 150), (int) (HEIGHT - (map.getHeight() / 2)), mPaint); if (index == 0) { } if (map.isRecycled()) { map.recycle(); } } if (!isstart) { if (index < KidbotRobotApplication.animBlink .getFrames().size()) { index++; if (index == KidbotRobotApplication.animBlink .getFrames().size()) { index--; isstart = true; if (rand.nextInt(10) <= 2) { index = 1; } } } else { index--; isstart = true; } } else { if (index > 0) { index--; if (index == 0) { isstart = false; } } else { index++; isstart = false; } } if (!isblinkfirst) { index = 0; } else { if (index == KidbotRobotApplication.animBlink .getFrames().size() - 1) { isblinkfirst = false; index = 0; handler.sendEmptyMessageDelayed(0, 1000 * (4 + rand.nextInt(4))); } } break; case FaceBean.ANGRY: frames = KidbotRobotApplication.animAngry.getFrames() .get(index); if (frames.getFrame().getW() <= 0) { } else { Rect rect = new Rect(frames.getFrame().getX(), frames.getFrame().getY(), frames.getFrame() .getX() + frames.getFrame().getW(), frames.getFrame().getH() + frames.getFrame().getX()); WeakReference weakBitmap = weakBitmaps .get(index); Bitmap map = null; if (weakBitmap == null) { map = bitmapRegionDecoder.decodeRegion(rect, options); weakBitmaps.put(index, new WeakReference (map)); } else { map=weakBitmap.get(); if (map == null) { map = bitmapRegionDecoder.decodeRegion( rect, options); weakBitmaps.put(index, new WeakReference (map)); } } if (map == null) { holder.unlockCanvasAndPost(canvas); continue; } mPaint.setXfermode(new PorterDuffXfermode( Mode.CLEAR)); canvas.drawPaint(mPaint); mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); Bitmap dstbmp =null; weakBitmap=cweakBitmaps.get(index); if(weakBitmap==null){ dstbmp = Bitmap.createBitmap(map, 0, 0, map.getWidth(), map.getHeight(), matrix, true); cweakBitmaps.put(index, new WeakReference (dstbmp)); }else{ dstbmp=weakBitmap.get(); if(dstbmp==null){ dstbmp = Bitmap.createBitmap(map, 0, 0, map.getWidth(), map.getHeight(), matrix, true); cweakBitmaps.put(index, new WeakReference (dstbmp)); } } canvas.drawBitmap( map, frames.getSpriteSourceSize().getX() + (int) (WIDTH - (map.getWidth() * 1) - 150), frames.getSpriteSourceSize().getY() + (int) (HEIGHT - (map.getHeight() / 2)), mPaint); canvas.drawBitmap(dstbmp, frames .getSpriteSourceSize().getX() + (int) (WIDTH + 150), frames .getSpriteSourceSize().getY() + (int) (HEIGHT - (map.getHeight() / 2)), mPaint); if (dstbmp.isRecycled()) { dstbmp.recycle(); } if (map.isRecycled()) { map.recycle(); } } if (!isstart) { if (index < KidbotRobotApplication.animAngry .getFrames().size()) { index++; if (index == KidbotRobotApplication.animAngry .getFrames().size()) { index--; isstart = true; } } else { index--; isstart = true; } } else { if (index > 0) { index--; if (index == 0) { isstart = false; } } else { index++; isstart = false; } } break; case FaceBean.HAPPY: frames = KidbotRobotApplication.animHappy.getFrames() .get(index); if (frames.getFrame().getW() <= 0) { } else { Rect rect = new Rect(frames.getFrame().getX(), frames.getFrame().getY(), frames.getFrame() .getX() + frames.getSourceSize().getW(), frames.getFrame().getY() + frames.getSourceSize().getH()); WeakReference weakBitmap = weakBitmaps .get(index); Bitmap map = null; if (weakBitmap == null) { map = bitmapRegionDecoder.decodeRegion(rect, options); weakBitmaps.put(index, new WeakReference (map)); } else { map=weakBitmap.get(); if (map == null) { map = bitmapRegionDecoder.decodeRegion( rect, options); weakBitmaps.put(index, new WeakReference (map)); } } if (map == null) { holder.unlockCanvasAndPost(canvas); continue; } mPaint.setXfermode(new PorterDuffXfermode( Mode.CLEAR)); canvas.drawPaint(mPaint); mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC)); Bitmap dstbmp =null; weakBitmap=cweakBitmaps.get(index); if(weakBitmap==null){ dstbmp = Bitmap.createBitmap(map, 0, 0, map.getWidth(), map.getHeight(), matrix, true); cweakBitmaps.put(index, new WeakReference (dstbmp)); }else{ dstbmp=weakBitmap.get(); if(dstbmp==null){ dstbmp = Bitmap.createBitmap(map, 0, 0, map.getWidth(), map.getHeight(), matrix, true); cweakBitmaps.put(index, new WeakReference (dstbmp)); } } canvas.drawBitmap( map, frames.getSpriteSourceSize().getX() + (int) (WIDTH &nbs