Android SurfaceView android-SurfaceView 类
Android SurfaceView View 和 SurfaceView View 类是 android 的一个超类,每一个 View 都有一个用于绘画的画布,这 个画布可以进行任意的扩展。有的时候我们需要自定义 VIew 实现自己想 要的视图。 view 、 SurfaceView 是游戏开发中经常用到的视图。 View :显示视图,内置画布,提供图形绘制函数、触屏事件、按键事件 函数等;必须在 UI 主线程内更新画面,速度较慢。 SurfaceView :基于 view 视图进行拓展的视图类,更适合 2D 游戏的开发; 是 view 的子类,类似使用双缓机制,在新的线程中更新画面所以刷新界面 速度比 view 快。
Android SurfaceView SurfaceView 类 SurfaceView 是从 View 基类中派生出来的显示类,直接子类有 GLSurfaceView 和 VideoView , GL 和视频播放以及 Camera 摄像头一般均使用 SurfaceView. SurfaceView 可以控制表面的格式,比如大小、显示在屏幕中的位置,最 关键是的提供了 SurfaceHolder 类,使用 getHolder 方法获取,相关的方法有 lockCanvas() 、 lockCanvas(Rect dirty) 、 removeCallback(Callback callback) 、 unlockCanvasAndPost(Canvas canvas) 控制图形以及绘制。 对于 Surface , Android 底层还提供了 GPU 加速功能,所以一般实时性很强的 应用中主要使用 SurfaceView 而不是直接从 View 构建,同时 Android 后面用 到的 OpenGL 中的 GLSurfaceView 也是从该类实现。
Android SurfaceView callback 接口 只要继承 SurfaceView 类并实现 SurfaceHolder.Callback 接口就可以实现 一个自定义的 SurfaceView , SurfaceHolder.Callback 在底层的 Surface 状 态发生变化的时候通知 View , SurfaceHolder.Callback 具有如下的接口 : surfaceCreated(SurfaceHolder holder) :当 Surface 第一次创建后会立即 调用该函数。程序可以在该函数中做些和绘制界面相关的初始化工作 ,一般情况下都是在另外的线程来绘制界面,所以不要在这个函数中 绘制 Surface 。 surfaceChanged(SurfaceHolder holder, int format, int width,int height) : 当 Surface 的状态(大小和格式)发生变化的时候会调用该函数,在 surfaceCreated 调用后该函数至少会被调用一次。 注意:一个 SurfaceView 只在 SurfaceHolder.Callback.surfaceCreated() 和 SurfaceHolder.Callback.surfaceDestroyed() 调用之间是可用的,其他时间是得不到 它的 Canvas 对象的( null )。
Android SurfaceView Android-surfaceView 与 View 的区别 SurfaceView 和 View 最本质的区别在于, surfaceView 是在一个新起的单独线程中可 以重新绘制画面,而 View 必须在 UI 的主线程中更新画面。那么在 UI 的主线程中更新 画面 可能会引发问题,比如更新画面的时间过长,那么主 UI 线程会被正在绘制的 函数阻塞。那么将无法响应按键、触屏等消息。使用 surfaceView ,由于是在新的 线程中更新画面所以不会阻塞 UI 主线程。但这也带来了另外一个问题,就是事件 同步。比如触屏了一下,需要 surfaceView 中 thread 处理,一般就需要有一个 event queue 的设计来保存 touch event ,这会稍稍复杂一点,因为涉及到线程同步。所以 基于以上,根据游戏特点,一般分成两类: (1 ) 被动更新画面的。比如棋类,这种用 view 就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate 。 因为这种情况下,这一次 Touch 和下 一次的 Touch 需要的时间比较长些,不会产生影响。 (2 ) 主动更新。比如一个人在一直跑动。这就需要一个单独的 thread 不停的重绘人 的状态,避免阻塞主线程。所以显然 view 不合适,需要 surfaceView 来控制。
Android SurfaceView 使用 SurfaceView 绘制矩形 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MyView(this)); } class MyView extends SurfaceView implements SurfaceHolder.Callback{ SurfaceHolder holder; public MyView(Context context) { super(context); holder=getHolder(); holder.addCallback(this); } public void surfaceCreated(SurfaceHolder holder) { new Thread(new MyThread()).start(); }
Android SurfaceView 使用 SurfaceView 绘制矩形 class MyThread implements Runnable{ public void run() { // 锁定画布,通过其返回的画布对象 canvas ,在其上面画图 Canvas canvas=holder.lockCanvas(); canvas.drawColor(Color.WHITE); Paint paint=new Paint(); paint.setColor(Color.YELLOW); canvas.drawRect(10, 10, 220, 180, paint); holder.unlockCanvasAndPost(canvas);// 结束锁定画图,并提交编辑 }
Android SurfaceView SurfaceView 绘图机制 重写 CallBack 对象的 surfaceCreate 方法 ,在该方法中为 SurfaceView 绘制背景, 并避免背景图片被下一次 lockCanvas 遮 挡。 监听触摸事件,每次触摸屏幕时,程序 会锁定触碰周围的区域,那么就只更新 该区域的数据,而且本次的 lockCanvas 会遮挡上一次的 lockCanvas 后绘制的图 形。 注:第一次绘制的图形可能会被第二次 的 lockCanvas 遮挡,第三次的 lockcanvas 又可能遮挡第二次 lockCanvas 的区域,但不可能遮挡第一 次的 lockCanvas 区域
Android SurfaceView SurfaceView 绘图机制 holder.addCallback(new Callback() { public void surfaceDestroyed(SurfaceHolder holder) {} public void surfaceCreated(SurfaceHolder holder) { Canvas canvas=holder.lockCanvas(); Bitmap bitmap=BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.sun); canvas.drawBitmap(bitmap, 0, 0, null); holder.unlockCanvasAndPost(canvas); holder.lockCanvas(new Rect(0,0,0,0)); holder.unlockCanvasAndPost(canvas); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} });
Android SurfaceView SurfaceView 绘图机制 sf.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if(event.getAction()==MotionEvent.ACTION_DOWN){ int cx=(int) event.getX(); int cy=(int) event.getY(); Canvas canvas=holder.lockCanvas(new Rect(cx-50,cy-50,cx+50,cy+50)); canvas.save(); canvas.rotate(30, cx, cy); paint.setColor(Color.YELLOW); canvas.drawRect(cx-40, cy-40, cx, cy, paint); canvas.restore(); paint.setColor(Color.GREEN); canvas.drawRect(cx, cy, cx+40, cy+40, paint); holder.unlockCanvasAndPost(canvas); } return false; } });