1、概述
今天给大家带来SurfaceView的一个实战案例,话说自定义View也是各种写,一直没有写过SurfaceView,这个玩意是什么东西?什么时候用比较好呢?
可以看到SurfaceView也是继承了View,但是我们并不需要去实现它的draw方法来绘制自己,为什么呢?
因为它和View有一个很大的区别,View在UI线程去更新自己;而SurfaceView则在一个子线程中去更新自己;这也显示出了它的优势,当制作游戏等需要不断刷新View时,因为是在子线程,避免了对UI线程的阻塞。
知道了优势以后,你会想那么不使用draw方法,哪来的canvas使用呢?
大家都记得更新View的时候draw方法提供了一个canvas,SurfaceView内部内嵌了一个专门用于绘制的Surface,而这个Surface中包含一个Canvas。
有了Canvas,我们如何获取呢?
SurfaceView里面有个getHolder方法,我们可以获取一个SurfaceHolder。通过SurfaceHolder可以监听SurfaceView的生命周期以及获取Canvas对象。
2、一般的写法
综上所述,一般SurfaceView类中我们会这么写代码:
- public class SurfaceViewTemplate extends SurfaceView implements Callback, Runnable
- {
-
- private SurfaceHolder mHolder;
-
-
-
- private Canvas mCanvas;
-
-
-
- private Thread t;
-
-
-
- private boolean isRunning;
-
- public SurfaceViewTemplate(Context context)
- {
- this(context, null);
- }
-
- public SurfaceViewTemplate(Context context, AttributeSet attrs)
- {
- super(context, attrs);
-
- mHolder = getHolder();
- mHolder.addCallback(this);
-
-
-
-
-
- setFocusable(true);
- setFocusableInTouchMode(true);
-
- this.setKeepScreenOn(true);
-
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder)
- {
-
-
- isRunning = true;
- t = new Thread(this);
- t.start();
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height)
- {
-
-
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder)
- {
-
- isRunning = false;
- }
-
- @Override
- public void run()
- {
-
- while (isRunning)
- {
- draw();
- }
-
- }
-
- private void draw()
- {
- try
- {
-
- mCanvas = mHolder.lockCanvas();
- if (mCanvas != null)
- {
-
- }
- } catch (Exception e)
- {
- } finally
- {
- if (mCanvas != null)
- mHolder.unlockCanvasAndPost(mCanvas);
- }
- }
- }
结合上面我们的介绍,我们在构造中通过getHolder拿到SurfaceHolder对象,然后设置一个addCallback回调,去监听SurfaceView的生命周期,生命周期有三个方法,分别为create,change,destory;我们一般在create里面进行初始化的一些操作,然后开启线程;在destroy里面设置关闭线程;
所有的绘制流程都是线程的run方法里面,可以看到我们的draw方法。
注意下,我们在draw里面进行了try catch然后很多的判空,主要是因为,当用户点击back或者按下home键以后,surfaceview会被销毁;
mHolder.lockCanvas();返回的就是null了,所以为了避免造成空指针错误,我们各种判null,甚至还加了个try catch。
说了这么多,竟然没看到效果图,这怎么能行~~
3、效果图
![](https://img-blog.csdn.net/20141204131218761)
就这么个效果,当然了模拟器录制的效果肯定没有真机上效果流畅。
结合上面我们给出的模版,我们需要改变的就是,在create回调里面需要去初始化一些变量,在draw方法里面去绘制我们的文本、图片、扇形块块等等。整体架构没有变化。
4、转盘的制作
1、构造方法以及变量
- public class LuckyPanView extends SurfaceView implements Callback, Runnable
- {
-
- private SurfaceHolder mHolder;
-
-
-
- private Canvas mCanvas;
-
-
-
- private Thread t;
-
-
-