Android学习之surfaceView简单入门

什么是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相当于是另外一个绘图线程,它不会阻碍主线程,并且在底层实现了双缓冲机制。

双缓冲技术是游戏开发中的一个重要技术。当一个动画争先显示时,程序又在改变它,前面还么有显示完,程序又请求重新绘制,这样屏幕就会不停的闪烁。而双缓冲技术是把要处理的图片在内存中处理好之后,再将其显示在屏幕上,双缓冲主要是为了解决反复局部刷屏带来的闪烁。把要画的东西先画到一个内存区域里,然后整体的一次性画出来。

扫描二维码关注公众号,回复: 2634459 查看本文章

使用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






猜你喜欢

转载自blog.csdn.net/qq_36391075/article/details/79337485