Android初级开发----关于SurfaceView(平面视图的笔记)

本文介绍了Android开发中SurfaceView的基本概念及其绘图机制。通过一个示例程序详细讲解了如何利用SurfaceView及双缓冲技术实现在新线程上对屏幕进行高效绘制,包括创建线程、上锁画布、绘画过程及解锁提交等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android初级开发—-关于SurfaceView(平面视图的笔记)

  1. 问题引入:之前了解了View类下的ondraw()的用法,突然萌发个小想法,心血来潮想写个简单的打飞机小游戏.在简单实现飞机移动之后,一系列问题接踵而来.飞机发射子弹怎么办?利用新线程重复循环发送子弹?那子弹如何表示,如果用图片,每次子弹移动就要重绘的话,那要添加多少图片,而且实际运行的时候界面要求不断刷新会不会卡爆?理智想想,还是不能太过急功近利,先从小问题开始入门.
    在网上初略逛了一下之后,偶然看到凯哥的教学视频—-《凯哥教你打飞机》,才了解到一个View的子类SurfaceView.
    那么,SurfaceView 究竟是什么呢?又是如何用呢?
    • 二级缓存概念的引入
      大概的意思是当程序在指定View绘制的时候,程序不直接绘制于View组件,而是先在内存处理Bitmap,再更新到View上面.
      Bitmap在android.graphics包中.
      1. 定义一个二级缓存照片 Bitmap bm = null;
      2. bm =Bitmap.createBitmap(x,y, Bitmap.Config.ARGB_8888); //创建二级缓存照片,设置画质最高8888
      3. Canvas c = new Canvas(bm) ,或者c.setBitmap(bm); 并且在c上绘画 ,意为把画板套在缓冲区上
      4. canvas.drawBitmap(bm,0,0,new Paint()); //把缓冲区的对象绘制到View上面去

再来看一个View的子类

  • SurfaceView —-平板画面,它常常用于游戏,绘图,影视和照相处理的区域.传统的View虽然亦可绘图然而View的绘图机制缺乏双缓冲机制,而且主要的不足是新线程无法直接更新View组件.
    官方文档:

    Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen.
    •All SurfaceView and SurfaceHolder.Callback methods will be called from the thread running the SurfaceView’s window (typically the main thread of the application). They thus need to correctly synchronize with any state that is also touched by the drawing thread.
    •You must ensure that the drawing thread only touches the underlying Surface while it is valid – between SurfaceHolder.Callback.surfaceCreated() and SurfaceHolder.Callback.surfaceDestroyed().


大致翻译: SurfaceView是一个View的继承类,你可以 控制它的尺寸和格式.
SurfaceView必须在主线程里调用 SurfaceHolder.Callback.surfaceCreated() SurfaceHolder.Callback.surfaceDestroyed(). 是Surface创建和销毁时候会回调的方法,有点抽象,大概是说Surface只在这两个阶段之间有效. **SurfaceView**是一个绘图容器,虽然它的Callback方法只能在UI线程调用,但是你可以用它新建一个非UI线程上对屏幕绘画,巧妙的避免了主线程的阻塞现象,这是一个很大的优势.
  • Surfaceview绘图机制
    一般来说,在新线程对Canvas(画布)进行绘画之前,需要对画布进行lock(上锁),
    步骤

    1. SurfaceViewgetHeloder()获取SurfaceHolder
    2. 利用SurfaceHolder对作画区域进行上锁
      Canvas 类有一个lockCanvas(Rect dirty)方法 参数dirty是一个Ract划分区域,如果不填则表示整个SurfaceView对象.通过这个方法获取指定SurfaceView的Canvas,后续程序就可以对上锁的区域进行绘画.
    3. 绘画完成之后则,调用unlockCanvasAndPost(canvas)解锁并且提交画布区域.
      引用这位仁兄的见解:http://www.cnblogs.com/xuling/archive/2011/06/06/android.html

      • 注意的是:

      SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(Surface—表面,这个概念在 图形编程中常常被提到。基本上我们可以把它当作显存的一个映射,写入到Surface 的内容可以被直接复制到显存从而显示出来,这使得显示速度会非常快),而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。

抽象的balabala一大堆,下面我们来看示例代码:
仿造凯哥的一个SurfaceView测试,它实现了创建一个新线程在指定区域随机生成不同颜色的线条并且不断绘画.

package com.example.dh.bitmap_test;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.Random;

/**
 * Created by DH on 2016/4/14.      使用二级缓存绘画
 */
public class GameView extends SurfaceView implements Runnable,SurfaceHolder.Callback{
    //先激活才能绘画,      优点可以用线程来绘画.
    public GameView(Context context){
        super(context);
        getHolder().addCallback(this);//注册回调方法,通知下方方法

        gameBitmap=Bitmap.createBitmap(700,1200, Bitmap.Config.ARGB_8888);       //创建二级缓存照片,设置画质最高
    }

    private boolean runState = false;   //线程状态
    private SurfaceHolder holder = null;

    private Bitmap gameBitmap=null;//二级缓存照片

    int linecount = 0;

    public void run() {
        Random ran = new Random();  //随机类
        try {
            while (true) {
                Canvas canvas = holder.lockCanvas(); //上锁获得绘画画布
                //可以多线程控制 谁锁上谁就可以使用 而且(可以设定锁定范围(矩形)) holder.lockCanvas(new Rect(0,0,400,800));

                Canvas c = new Canvas(gameBitmap);                //建立绘画对象,在二级缓存上面作画

                //绘画操作
                Paint p = new Paint();
//                p.setColor(Color.WHITE);                            //画笔设置颜色
//                c.drawRect(new Rect(0,0,700,1200),p);                //指定区域刷白色 可以隐藏之前的线

                p.setColor(Color.rgb(ran.nextInt(255), ran.nextInt(255), ran.nextInt(255)));  //随机生成颜色
                c.drawLine(ran.nextInt(1000), ran.nextInt(1000),    //★此处画在c上面的gameBitmap 后来再调用canvas.drawBitmap(gameBitmap,0,0,new Paint());还原于 canvas
                        ran.nextInt(1000), ran.nextInt(1000), p); //随机画线(起始坐标,结束坐标,画笔)
                linecount ++;   //线条数量+1
                Log.d("GV","线条绘画,数量:"+ linecount);

                canvas.drawBitmap(gameBitmap,0,0,new Paint());      //把缓冲区的对象绘制到View上面去

                holder.unlockCanvasAndPost(canvas);//解锁,提交绘画内容
                Thread.sleep(100);
            }
        }catch (Exception e){
            Log.e("GV","异常",e);
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //视图创建通知
        this.holder = holder; //记得传递!

        runState = true;
        new Thread(this).start();//线程激活
        Log.d("GV", "界面创建");

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        //界面改变通知
        Log.d("GV","界面改变");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //视图销毁通知
        Log.d("GV","界面销毁");
        runState = false;//控制关闭线程
    }

  }

简单的说,这个程序会建立一个SurfaceView ,并且在上面不断随机生成任意颜色的直线。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值