SurfaceView

 使用SurfaceView
只要继承SurfaceView类并实现SurfaceHolder.Callback接口就可以实现一个自定义的SurfaceView了,SurfaceHolder.Callback在底层的Surface状态发生变化的时候通知View,SurfaceHolder.Callback具有如下的接口:
 surfaceCreated(SurfaceHolder holder):

Surface第一次创建后会立即调用该函数。程序可以在该函数中做些和绘制界面相关的初始化工作,一般情况下都是在另外的线程来绘制界面,所以不要在这个函数中绘制Surface。 
 surfaceChanged(SurfaceHolder holder, int format, int width,int height):

Surface的状态(大小和格式)发生变化的时候会调用该函数,在surfaceCreated调用后该函数至少会被调用一次。 
 surfaceDestroyed(SurfaceHolder holder):

Surface被摧毁前会调用该函数,该函数被调用后就不能继续使用Surface了,一般在该函数中来清理使用的资源。 
 
通过SurfaceView的getHolder()函数可以获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内。虽然Surface保存了当前窗口的像素数据,但是在使用过程中是不直接和Surface打交道的,由SurfaceHolder的Canvas lockCanvas()或则Canvas lockCanvas(Rect dirty)函数来获取Canvas对象,通过在Canvas上绘制内容来修改Surface中的数据。如果Surface不可编辑或则尚未创建调用该函数会返回null,在 unlockCanvas() 和 lockCanvas()中Surface的内容是不缓存的,所以需要完全重绘Surface的内容,为了提高效率只重绘变化的部分则可以调用lockCanvas(Rect dirty)函数来指定一个dirty区域,这样该区域外的内容会缓存起来。在调用lockCanvas函数获取Canvas后,SurfaceView会获取Surface的一个同步锁直到调用unlockCanvasAndPost(Canvas canvas)函数才释放该锁,这里的同步机制保证在Surface绘制过程中不会被改变(被摧毁、修改)。
当在Canvas中绘制完成后,调用函数unlockCanvasAndPost(Canvas canvas)来通知系统Surface已经绘制完成,这样系统会把绘制完的内容显示出来。

为了充分利用不同平台的资源,发挥平台的最优效果可以通过SurfaceHolder的setType函数来设置绘制的类型,目前接收如下的参数:
SURFACE
_TYPE_NORMAL:用RAM缓存原生数据的普通Surface 
SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface 
SURFACE_TYPE_GPU:适用于GPU加速的Surface 
SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了。 
 
目前OPhone还不支持GIF动画图片的显示,这里就通过一个SurfaceView来展示如何定制一个支持GIF动画的View,同时从该示例(注释)中也可以看出如何使用SurfaceView。
 
首先创建一个GifView继承在SurfaceView,代码如下:

class GifView extends SurfaceView implements Callback
 { 
//GifThread是用来绘制的后台线程,一般使用SurfaceView都会使用一个
 //后台线程来做绘制的工作 private GifThread mGifThread; //GifDecoder是一个Gif图片格式的解析器,用来解析Gif图片的每帧数据和显示时间。
 private GifDecoder mGifDecoder; public GifView(Context context,int gifId) 
{ super(context);
 //获取Gif图片数据 InputStream is = context.getResources().openRawResource(gifId); 
//解析Gif图片数据 
mGifDecoder = new GifDecoder();
 mGifDecoder.read(is); 
try { is.close(); 
} catch (IOException e) 
{ e.printStackTrace(); } 
is = null; 
//获取SurfaceHolder SurfaceHolder holder = getHolder(); 
//如果有必要可以设置合适的SurfaceType 
//holder.setType(SurfaceHolder.SURFACE_TYPE_HARDWARE); 
//设置回调函数 holder.addCallback(this); 
//创建Gif绘制线程 mGifThread = new GifThread(holder,this); } 
public void surfaceChanged(SurfaceHolderholder, int format, int width, int height) { //Do nothing }
 public void surfaceCreated(SurfaceHolderholder) { 
//当Surface创建成功后,启动绘制线程 mGifThread.setRunning(true); mGifThread.start(); }
 public void surfaceDestroyed(SurfaceHolderholder) { //当Surface即将摧毁的时候,停止绘制线程 boolean retry = true; mGifThread.setRunning(false); while (retry) { try { mGifThread.join(); retry = false; } catch (InterruptedException e) { // we will try it again and again... } } } } 在代码中都有详细的注释,这里就不再解释,下面是GifThread代码: class GifThread extends Thread { private SurfaceHolder mSurfaceHolder; private boolean mRunning; private int mCurrentFrame;//当前绘制的帧数 private long mLastTime;//上一帧绘制的时间 private int mFrameCount;//总帧数 private Bitmap[] mBitmap;//每帧的图片数据 private int[] mDelay;//每帧的显示时间 public GifThread(SurfaceHolder surfaceHolder, GifView gifView) { mSurfaceHolder = surfaceHolder; GifDecoder mGifDecoder = gifView.mGifDecoder; mLastTime = System.currentTimeMillis(); mFrameCount = mGifDecoder.getFrameCount(); mBitmap = new Bitmap[mFrameCount]; mDelay = new int[mFrameCount]; for (int i = 0; i < mFrameCount; i++) { mBitmap[i] = mGifDecoder.getFrame(i); mDelay[i] = mGifDecoder.getDelay(i); } mGifDecoder = null; } public void setRunning(boolean running) { mRunning = running; } private void doDraw(Canvas canvas) { mLastTime = System.currentTimeMillis();; canvas.drawBitmap(mBitmap[mCurrentFrame], new Matrix(), null); mCurrentFrame ++; } @Override public void run() { Canvas c; int delay = 0; while (mRunning) { c = null; if(mCurrentFrame != 0) { delay = mDelay[mCurrentFrame-1]; } if(mCurrentFrame == mFrameCount) { mCurrentFrame = 0; } long currentTime = System.currentTimeMillis(); long t = currentTime - mLastTime; //如果到下一帧绘制时间开始绘制下一帧 if(t >= delay) { try { //获取Canvas来绘制界面 c = mSurfaceHolder.lockCanvas(null); //通过mSurfaceHolder来同步绘制操作 synchronized (mSurfaceHolder) { doDraw(c); } } finally { // 在finally中执行该操作,这样当上面的代码抛出异常的时候 //不会导致Surface出去不一致的状态。 if (c != null) { mSurfaceHolder.unlockCanvasAndPost(c); } } } } } } 







 

最后创建一个Activity来测试下GifView:
 
public class SurfaceActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new GifView(this,R.raw.pic)); } } 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值