SurfaceView继承了View,可是咱们并不须要去实现它的draw方法来绘制本身,为何呢?由于它和View有一个很大的区别,View在UI线程去更新本身;而SurfaceView则在一个子线程中去更新本身;这也显示出了它的优点,当制做游戏等须要不断刷新View时,由于是在子线程,避免了对UI线程的阻塞。java
SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面。因为拥有独立的绘图表面,所以SurfaceView的UI就能够在一个独立的线程中进行绘制。又因为不会占用主线程资源,SurfaceView一方面能够实现复杂而高效的UI,另外一方面又不会致使用户输入得不到及时响应。android
普通的Android控件,例如TextView、Button和CheckBox等,它们都是将本身的UI绘制在宿主窗口的绘图表面之上,这意味着它们的UI是在应用程序的主线程中进行绘制的。因为应用程序的主线程除了要绘制UI以外,还须要及时地响应用户输入,不然的话,系统就会认为应用程序没有响应了,所以就会弹出一个ANR对话框出来。对于一些游戏画面,或者摄像头预览、视频播放来讲,它们的UI都比较复杂,并且要求可以进行高效的绘制,所以,它们的UI就不适合在应用程序的主线程中进行绘制。这时候就必需要给那些须要复杂而高效UI的视图生成一个独立的绘图表面,以及使用一个独立的线程来绘制这些视图的UI。canvas
只要继承SurfaceView类并实现SurfaceHolder.Callback接口就能够实现一个自定义的SurfaceView了。缓存
SurfaceView里面有个getHolder方法,咱们能够获取一个SurfaceHolder。经过SurfaceHolder能够监听SurfaceView的生命周期以及获取Canvas对象。Canvas至关于画布,你能够在上面画图,画线,画字以及其余图形。 函数
package com.example.shengchanglu.test; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; /** * Created by shengchanglu on 15/9/17. */ public class MySurfaceView extends SurfaceView implements Callback, Runnable { private Thread th; private SurfaceHolder sfh; private Canvas canvas; private Paint paint; private Bitmap bmp; private int bmp_x, bmp_y; private boolean himi; public MySurfaceView(Context context, AttributeSet attrs) { super(context); this.setKeepScreenOn(true); bmp = BitmapFactory.decodeResource(getResources(), R.drawable.logo); sfh = this.getHolder(); sfh.addCallback(this); //备注1 paint = new Paint(); paint.setAntiAlias(true); this.setLongClickable(true); } public void surfaceCreated(SurfaceHolder holder) {
int screenW = this.getWidth();
int screenH = this.getHeight();//surfaceView 在调用surfaceCreated前建立起来,在这里才能拿到长宽。而不是在上面的构造函数中
himi = true; th = new Thread(this, "himi_Thread_one");//备注2 th.start(); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
} public void surfaceDestroyed(SurfaceHolder holder) { himi = false;//备注3 } public void draw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.WHITE); canvas.drawBitmap(bmp, bmp_x, bmp_y, paint); } } catch (Exception e) { } finally { if (canvas != null) sfh.unlockCanvasAndPost(canvas); } } public void run() { while (himi) {//备注4 draw(); try { Thread.sleep(100); } catch (Exception ex) { } } } }
/备注1this
SurfaceHolder.Callback接口:线程
只要继承SurfaceView类并实现SurfaceHolder.Callback接口就能够实现一个自定义的SurfaceView了,SurfaceHolder.Callback在底层的Surface状态发生变化的时候通知View,SurfaceHolder.Callback具备以下的接口:code
surfaceCreated(SurfaceHolder holder):当Surface第一次建立后会当即调用该函数。程序能够在该函数中作些和绘制界面相关的初始化工做,通常状况下都是在另外的线程来绘制界面,因此不要在这个函数中绘制Surface。orm
surfaceChanged(SurfaceHolder holder, int format, int width,int height):当Surface的状态(大小和格式)发生变化的时候会调用该函数,在surfaceCreated调用后该函数至少会被调用一次。视频
SurfaceHolder 类:
它是一个用于控制surface的接口,它提供了控制surface 的大小,格式,上面的像素,即监视其改变的。
SurfaceView的getHolder()函数能够获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内。虽然Surface保存了当前窗口的像素数据,可是在使用过程当中是不直接和Surface打交道的,由SurfaceHolder的Canvas lockCanvas()或则Canvas lockCanvas()函数来获取 Canvas对象,经过在Canvas上绘制内容来修改Surface中的数据。若是Surface不可编辑或则还没有建立调用该函数会返回null,在 unlockCanvas() 和 lockCanvas()中Surface的内容是不缓存的,因此须要彻底重绘Surface的内容,为了提升效率只重绘变化的部分则能够调用 lockCanvas(Rect rect)函数来指定一个rect区域,这样该区域外的内容会缓存起来。在调用lockCanvas函数获取Canvas后,SurfaceView会获取Surface的一个同步锁直到调用unlockCanvasAndPost(Canvas canvas)函数才释放该锁,这里的同步机制保证在Surface绘制过程当中 不会被改变(被摧毁、修改)。