您的当前位置:首页正文

SurfaceView的特性总结

来源:要发发知识网

为了Native开发中嵌入cocos2d和unity3d的游戏元素,需要在某些场景下播放一组游戏特效,例如被攻击, 侦查时的全屏闪烁Flash效果和几十帧的动画轮播。

考虑到游戏特效的复杂度,若使用常规的ImageView, 由于需要在主线程中绘制动画,对性能的损耗较大,在配置较差的机器上会卡顿和影响用户操作,体验不佳。

所以想到了用SurfaceView来绘制。关于SurfaceView的特性,简单归纳如下:

  1. SurfaceView和普通View的区别在于它拥有一个可绘制Surface,这使它不需要绘制在宿主窗口上。
  2. SurfaceView允许额外的线程(一个或者多个)来绘制图形到它的Surface上,这使它可以自定义绘制的帧数并不会阻塞主线程和影响用户的输入。
  3. SurfaceView是Z轴排序(XYZ坐标轴的Z轴),这意味在它可以显示在宿主窗口之下(默认)或者之上。
  4. SurfaceView内部维护双缓冲,显示效果比View流畅,但相比View更耗内存。

SurfaceView和普通View对比的优缺点:

优点

  • 不用在主线程中绘制,不会卡顿UI
  • 绘制速度快,支持多线程绘制
  • 可以自由控制绘制在Activity图层上方或者下方

缺点

  • 内部维护双缓冲,比普通的View更耗内存

以下是一些使用备忘点:

1. 清除画布

// 清空画布
Canvas canvas = mHolder.lockCanvas();
if (canvas != null) {
    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    mHolder.unlockCanvasAndPost(canvas);
}

2. 多次绘制时清除上次绘制残影

Canvas canvas = mHolder.lockCanvas();
if (canvas != null) {
    Paint paint = new Paint();
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    canvas.drawPaint(paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
    onDraw(canvas, paint);
    mHolder.unlockCanvasAndPost(canvas);
}
sleep(mFrameTime);

3. 设置背景透明

一般只有当SurfaceView的图层需要显示在窗口顶层时才会需要设置为窗口透明,这种情况可以通过以下方式设置:

mHolder = getHolder();
// 设置SurfaceView显示在窗口顶层
setZOrderOnTop(true);
// 设置SurfaceView透明
mHolder.setFormat(PixelFormat.TRANSLUCENT);

4. 多个线程同时绘制时需要对Canvas添加同步锁

Canvas canvas = mHolder.lockCanvas();
if (canvas != null) {
    synchronized (canvas){
        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        canvas.drawPaint(paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
        onDraw(canvas, paint);
        mHolder.unlockCanvasAndPost(canvas);
    }
}

5. 绘制完成后必须调用mHolder.unlockCanvasAndPost(canvas)

// 解锁画布并提交绘制
mHolder.unlockCanvasAndPost(canvas);

6. 生命周期

  1. SurfaceView可见时,调用surfaceCreated和surfaceChanged
  2. SurfaceView不可见时,调用surfaceDestroyed
  3. 被新的Activity覆盖、回到后台时,调用surfaceDestroyed
  4. 锁屏时,不会调用surfaceDestroyed
  5. 若键盘弹出影响到SurfaceView的区域,调用surfaceChanged

文章的主要目的是分享和备忘,若有不足之处,还请帮忙指出!欢迎各位给我留言!