认识 SurfaceView

来源:互联网 发布:html链接数据库 编辑:程序博客网 时间:2024/06/05 15:07


SurfaceView是基于View视图进行扩展的视图类,适用于2D游戏开发,主要特点有:

【1】surfaceView中对于画布的重绘是由一个新的线程去绘制,因此可以处理一些耗时的操作

【2】surfaceView具有双重缓冲机制(view没有)

适用于动态实时更新的画面,比如游戏处理中就算主角啥事不做,旁边流水会动,飞行射击类,抽奖转盘的制作都是动态,需要不断的绘制元素状态,通常view更加适合被动更新的如棋牌类

1、SurfaceView基本框架

SurfaceView使用也比较好掌握,基本框架见如下代码:


/** *  * @author ELVIS *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);// TODO Auto-generated constructor stub}public SurfaceViewTemplate(Context context, AttributeSet attrs) {super(context, attrs);mHolder = getHolder();mHolder.addCallback(this); // 添加回调结构setFocusable(true);// 可获得焦点setFocusableInTouchMode(true);setKeepScreenOn(true);// 设置常亮}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// TODO Auto-generated method stubisRunning = true;t = new Thread(this);}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {// TODO Auto-generated method stub}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// TODO Auto-generated method stubisRunning = false;}@Overridepublic void run() {// TODO Auto-generated method stubwhile(isRunning){draw();//进行绘制}}private void draw() {//获取canvastry {mCanvas = mHolder.lockCanvas();if(mCanvas!=null){//draw }} catch (Exception e) {/*// TODO Auto-generated catch blocke.printStackTrace();*/}finally{//canvas 释放if(mCanvas!=null){mHolder.unlockCanvasAndPost(mCanvas);}}}}

这里做一些补充解释

【1】继承SurfaceView

【2】重要的SurfaceHolder,此类提供控制SurfaceView的大小,格式等等,并且监听其状态,因而实现Callback接口重写函数

SurfaceCreated:当surfaceView创建完成时响应的函数

surfaceChanged:当surfaceView状态发生改变时候响应函数

surfaceDetroy:当surfaceView状态摧毁时响应函数

【3】由于surfaceView不同于view,前者需要一个线程来完成更新,框架都差不多,不同的只是draw里面的东西复杂度(这里是核心)

【4】SurfaceView是通过SurfaceHolder来修改其数据,所以在SurfaceView上不再通过onDraw来绘图,而是通过surfaceHolder取到surfaceView的canvas,然后再进行绘制

因此即使重写view的ondraw函数在SurfaceView启动时也不会执行到

【5】在进行绘制的时候一般都是lockCanvas获取canvas同时对画布进行加锁,与之对应的还有unlockCanvasAndPost函数用于解锁画布和提交


2、刷屏方式

这里也是跟view绘图的区别所在。在view绘图中,View类本身提供俩种重绘函数(invalidate和postInvalidate),其内部已经封装了对画布的刷屏操作,所以每次在ondraw中重绘画布永远看不到之前绘制过的图形,但是在SurfaceView是自定义的绘制函数,而且每次获取到的canvas仍然是上次的画布,因此在使用surfaceView视图时,得到画布canvas之后首先做的事刷屏操作,否则界面状态是无法更新的,这点千万要留意

一般刷屏有以下几种方式

(1)每次绘图前,绘制一个等同于屏幕大小的图形覆盖在画布上面

(2)没次绘图前在此画布上填充一种颜色

(3)每次绘图前指定RGB来填充画布

public void myDraw(){Canvas canvas = mHolder.lockCanvas();//绘制矩形canvas.drawRect(0, 0,this.getWidth(),this.getHeight(),paint);//canvas.drawColor(Color.BLACK);//画布填充颜色//canvas.drawRGB(0, 0, 0);//指定RGB来填充颜色canvas.drawText("surfaceViewTest", textX, textY, paint);mHolder.unlockCanvasAndPost(canvas);}

3、surfaceVAiew 添加线程的一些要点


3.1线程

在上面也说过了,surfaceView靠自己的线程去绘制画布以及游戏逻辑,往往需要一个线程标志位 boolean flag,主要有以下两点说明

【1】便于消亡线程

线程启动就会执行其run函数,run函数结束后线程随之消亡。在游戏开发中使用的线程一般都会在run函数中使用一个while死循环,在其中来执行绘图或者其他逻辑,如果游戏暂停或者结束,为了便于销毁线程需要设置一个标志位来控制

【2】防止重复创建线程及程序异常

主要涉及到back和home操作

按back时的surfaceView状态变化 surfaceDestroyed——构造函数——surfaceCreated——surfaceChanged

按home时的surfaceView状态变化 surfaceDestroyed——surfaceCreated——surfaceChanged

即按back键视图会被重新加载,而且千万不要把线程初始化放在surfaceCreate之前否则玩家点击home,再回到游戏就会抛出异常,这是从home恢复时会直接进入surfaceCreate再次启动线程

通俗做法:线程的初始化和线程的启动都写在视图的surfaceCreateed创建函数中,并且将线程的标志位flag在视图摧毁的时候置为fasle,这样既可以避免“线程已经启动“的异常,还可以避免点击back按键无线增加线程数目的问题

3.2 刷新帧时间尽可能保持一致

一般是通过系统函数获取到一个时间戳start;处理函数之后再次获取一个时间戳end,假设游戏线程的休眠时间为X,则按照如下房事编写

if((end-start)<X){Thread.sleep(X-(end-start));}

最后用一串显示hello world代码来总结一下

public class MySurfaceView extends SurfaceView implements Callback, Runnable {// 用于控制surfacViewprivate SurfaceHolder mHolder;// 声明一个画笔private Paint paint;// 文本的坐标private int textX = 10, textY = 10;// 声明一个线程private Thread th;// 线程消亡的标志位private boolean flag;// 声明一个画布private Canvas canvas;// 声明屏幕的宽高private int screenW, screenH;public MySurfaceView(Context context) {super(context);// 实例化mHoldermHolder = this.getHolder();// 为surfaceView添加监听器mHolder.addCallback(this);// 实例化画笔paint = new Paint();// 实例化画笔颜色为白色paint.setColor(Color.WHITE);// 设置焦点setFocusable(true);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {screenW = this.getWidth();screenH = this.getHeight();flag = true;// 实例化线程th = new Thread(this);// 启动线程th.start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {// TODO Auto-generated method stub}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {flag = true;}@Overridepublic void run() {while (flag) {long start = System.currentTimeMillis();myDraw();logic();long end = System.currentTimeMillis();try {if (end - start < 50) {Thread.sleep(50 - (end - start));}} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}} <pre name="code" class="java">       /* 游戏处理逻辑 */private void logic() {// 处理游戏逻辑部分}private void myDraw() {try {canvas = mHolder.lockCanvas();if (canvas != null) {// 这里采用绘制矩形方式刷屏// 绘制矩形canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), paint);canvas.drawText("Hello World", textX, textY, paint);}} catch (Exception e) {} finally {if (canvas != null)mHolder.unlockCanvasAndPost(canvas);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {textX = (int) event.getX();textY = (int) event.getY();return true;}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {return super.onKeyDown(keyCode, event);}}




0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝凑单地址不一样怎么办 任性付还不了款怎么办 京东购物卷删了怎么办 荣耀手环3进水了怎么办 手机疏油层没了怎么办 快递到了处理中心不走了怎么办 京东取消了退款怎么办 我的订单删除了怎么办 近邻宝箱子误关怎么办 把收件人电话写错了怎么办 吧收件人电话写错了怎么办 速递易收件人电话写错怎么办 书包上的皮掉了怎么办 美亚很多商品不直邮中国怎么办 我想买刘涛用的化妆品贵妇膏怎么办 自提柜号码忘记了怎么办 京东商城误点确认收货怎么办 京东购物到货后怎么办 京东地址错了怎么办 没买运费险退货怎么办 没有买运费险退货怎么办 买的运费险换货怎么办 顾客买衣服说贵怎么办 卖衣服顾客说贵怎么办 汽车前保险杠刮蹭怎么办 洗手盆下水管堵了怎么办 装修好的卫生间漏水怎么办 马桶水箱盖碎了怎么办 马桶陶瓷盖碎了怎么办 电脑左右分屏了怎么办 在东东助手里安装软件怎么办 王者荣耀进入安全系统怎么办 京东限时达超时怎么办 京东京准达晚点怎么办 京东京准达超时怎么办 南京犬类免疫证怎么办 合肥犬类免疫证怎么办 快递号码写错了怎么办 网购下单后商家说没有货该怎么办 京东账号换手机怎么办 手机不发验证码怎么办