Chendd's Blog

世界上没有什么事情是一行代码不能解决的。如果有,那就两行。

Android学习日记6--SurfaceView视图

一、API关SurfaceView的介绍

       SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。

       Surface是纵深排序的,这表明它总在自己所在窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内 的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。

       你可以通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口。surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。

       Surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意:

  • 所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。
  • 由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。

二、SurfaceView流程

       继承SurfaceView并实现SurfaceHolder.Callback接口 —-> SurfaceView.getHolder()获得SurfaceHolder对象 —->SurfaceHolder.addCallback(callback)添加回调函数—->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布—-> Canvas绘画 —->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示

三、SurfaceView具体实现

       用SurfaceView实现上篇View视图一样的例子

image

讲解写在注释里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package com.example.gamesurfaceview2;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

//SurfaceView 还要继承CallBack接口
public class MySurfaceView extends SurfaceView implements Callback,Runnable{

    private SurfaceHolder sfh;
    private Paint paint;
    private int x,y;
    private Thread thread;
    private boolean flag;
    private Canvas canvas;
    private int w,h;

    public MySurfaceView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        //通过SurfaceHolder来和Can打交道
        sfh = this.getHolder();
        //添加监听
        sfh.addCallback(this);
        x =20;
        y =20;
        paint = new Paint();
        paint.setColor(Color.WHITE);
        setFocusable(true);
    }

    @Override
    /**
     * surfaceView发生改变时执行的方法
     */
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub

    }

    @Override
    /**
     * surfaceView创建时执行的方法
     */
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        h = this.getHeight();
        w = this.getWidth();
        flag = true;
        thread = new Thread(this);
        thread.start();
    }

    /**
     * 自己定义的绘画调用方法
     */
    private void Mydraw() {
        try {
            // 获取一个加锁的画布,防止被其他修改
            canvas = sfh.lockCanvas();
            if (canvas != null) {
                //-----------利用填充矩形的方式,刷屏
                ////绘制矩形
                //canvas.drawRect(0,0,this.getWidth(),
                //this.getHeight(), paint);
                //-----------利用填充画布,刷屏
                //        canvas.drawColor(Color.BLACK);
                //-----------利用填充画布指定的颜色分量,刷屏
                // 没重画图像会叠在一起
                canvas.drawRGB(0, 0, 0);
                canvas.drawText("Game", x, y, paint);
            }
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            if (canvas != null)
                // 解锁和提交画布
                sfh.unlockCanvasAndPost(canvas);
        }
    }

    @Override
    /**
     * surfaceView被销毁时执行的方法
     */
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub

    }


    @Override
    /**
     * 触摸屏幕事件
     */
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        x= (int) event.getX();
        y= (int) event.getY();
        return true;
    }


    /**
     * 游戏逻辑
     */
    private void logic() {

    }
    @Override
    public void run() {
        while (flag) {
            long start = System.currentTimeMillis();
            Mydraw();
            logic();
            long end = System.currentTimeMillis();
            try {
                // 50毫秒刷新一次
                if (end - start < 50) {
                    Thread.sleep(50 - (end - start));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}

注意:当画布没有重画覆盖时,会出现如下重叠效果:

Comments