什么是SurfaceView:
Surface是表层,表面的意思,也就是说Surface是指一个在表层的View对象。对于其他View来说,它们是绘制在表层的上面,而它就是充当表层本身。
SDK上是这样写的:
Provides a dedicated drawing surface embedded inside of a view hierarchy.
大概是说这是一个在视图层次结构中嵌入的专用绘图表面
所以它就是表面。
The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed
它的表面是Z,所以它在窗口的后面,保持着它的SurfaceView;SurfaceView在它的Window上打一个洞,让它的表面被显示出来
所以其他的VIew可以显示在Surface之上,我们也可以在添加一些层在SurfaceView之上。
Surface属于View的子类,它是专门为制作游戏而产生的。它支持PoenGL ES库,2D和3D
Android系统提供了View进行绘图处理,通过自定义View可以满足大部分的绘图需求。但是自定义的View是用于主动更新的,用户无法控制其绘制的速度,由于View是通过invalidate方法通知系统去调用onDraw方法进行重绘,而android系统是通过发出VSYNC信号来进行屏幕的重绘,刷新的时间是16ms,如果在16ms内View完成不了执行的操作,用户聚会看着卡顿,而在游戏界面,有很多逻辑,需要不停的刷新界面,如果是在主线程,就会造成卡顿,而SurfaceView相当于是另外一个绘图线程,它不会阻碍主线程,并且在底层实现了双缓冲机制。
双缓冲技术是游戏开发中的一个重要技术。当一个动画争先显示时,程序又在改变它,前面还么有显示完,程序又请求重新绘制,这样屏幕就会不停的闪烁。而双缓冲技术是把要处理的图片在内存中处理好之后,再将其显示在屏幕上,双缓冲主要是为了解决反复局部刷屏带来的闪烁。把要画的东西先画到一个内存区域里,然后整体的一次性画出来。
使用SurfaceView:
SurfaceView也是一个View,它也有自己的生命周期。因为它需要另外一个线程来执行绘制操作,所以可以在它生命周期初始化阶段开启一个新线程,然后开始执行绘制,当生命周期结束阶段结束绘制。这些都是由其内部一个SurfaceHolder对象完成的。
通过SurfaceHolder接口提供对底层表面的访问
创建SurfaceView:
创建自定义的SurfaceView需要继承SurfaceView并且实现连个接口:SurfaceHolder.Callback和Runnable
public class MyView extends SurfaceView implements SurfaceHolder.Callback,Runnable
对于SurfaceHolder.Callback方法,其实就是SurfaceView的生命周期:
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
通过SurfaceHolder对象的lockCanvans()方法,我们可以获取当前的Canvas绘图对象。接下来的操作就和自定义View中的绘图操作一样了。需要注意的是这里获取到的Canvas对象还是继续上次的Canvas对象,而不是一个新的对象。因此,之前的绘图操作都会被保留,如果需要擦除,则可以在绘制前,通过drawColor()方法来进行清屏操作。
在绘制的逻辑中通过lockCanvas()方法获取Canvas对象进行绘制,通过unlockCanvasAndPost(mCanvas)方法对画布内容进行提交。
正玄曲线例子:
public class MyView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
private Context mContext;
private SurfaceHolder mHolder;
private Canvas mCanvas;
private boolean mIsdrawing;
private Path mPath;
private Paint mPaint;
private int x = 0;
private int y = 0;
private final int TIME_IN_FRAME = 30;
public MyView(Context context) {
this(context,null);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mHolder = getHolder();
mHolder.addCallback(this);//注册回调接口
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mIsdrawing = true;
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.BLUE);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
protected void onDraw(Canvas canvas) {
setBackgroundColor(Color.WHITE);
}
@Override
public void run() {
while (mIsdrawing){
long startTime = System.currentTimeMillis();
synchronized (mHolder){
mCanvas = mHolder.lockCanvas();
if(x<=getWidth()){
x+=1;
}else{
x = 1;
}
y = (int)(100*Math.sin(x*2*Math.PI/180)+400);
mPath.lineTo(x,y);
mCanvas.drawPath(mPath,mPaint);
mHolder.unlockCanvasAndPost(mCanvas);
}
long entTime = System.currentTimeMillis();
int difftime = (int)(entTime - startTime);
while(difftime <= TIME_IN_FRAME){//为了确保画面稳定
difftime = (int)(System.currentTimeMillis() - startTime);
Thread.yield();
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mIsdrawing = false;
}
}
参考于:http://blog.csdn.net/android_cmos/article/details/68955134
https://www.jianshu.com/p/b037249e6d31