`
byandby
  • 浏览: 1696420 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

android SurfaceView 使用示例 why SurfaceView上 不可以用控件的轻微解释

阅读更多
    当我们需要开发一个复杂的游戏的时候,而且对程序的执行效率要求很高时,View类就不能满足需求了,这时必须用SurfaceView类进行开发。例如,对速度要求很高的游戏时,View类就不能满足需求了,这时必须使用SurfaceView类进行开发。例如,对速度要求很高的游戏,可以使用双缓冲来显示。游戏中的背景、人物、动画等都需要绘制在一个画布(Canvas)上,而SurfaceView可以直接访问一个画布,SurfaceView 是提供给需要直接画像素而不是使用窗体部件的应用使用的。 每个Surface创建一个Canvas对象(但属性时常改变),用来管理View和Surface上的绘图操作。
    在使用SurfaceView开发时需要注意的是,使用它绘图时,一般都是出现在最顶层。使用时还需要对其进行创建、销毁、情况改变时进行监视,这就要实现SurfaceHolder.Callback接口,如果要对被绘制的画布进行裁剪,控制其大小都需要使用SurfaceHolder来完成处理。在程序中,SurfaceHolder对象需要通过getHolder 方法来获得,同时还需要addCallback方法来添加
"回调函数"
    在一般的情况下,应用程序的View都是在相同的GUI线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如,按钮单击或者文本输入)。
    当需要快速地更新View的UI,或者当渲染代码阻塞GUI线程的时间过长的时候,SurfaceView就是解决上述问题的最佳选择。 SurfaceView封装了一个Surface对象,而不是Canvas。这一点很重要,因为Surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如,使用3D图形,创建游戏,或者实时预览摄像头,这一点特别有用。
1. 何时应该使用SurfaceView?

SurfaceView使用的方式与任何View所派生的类都是完全相同的。可以像其他View那样应用动画,并把它们放到布局中。

SurfaceView封装的Surface支持使用本章前面所描述的所有标准Canvas方法进行绘图,同时也支持完全的OpenGL ES库。

使用OpenGL,你可以再Surface上绘制任何支持的2D或者3D对象,与在2D画布上模拟相同的效果相比,这种方法可以依靠硬件加速(可用的时候)来极大地提高性能。

对于显示动态的3D图像来说,例如,那些使用Google Earth功能的应用程序,或者那些提供沉浸体验的交互式游戏,SurfaceView特别有用。它还是实时显示摄像头预览的最佳选择。

2. 创建一个新的SurfaceView控件

要创建一个新的SurfaceView,需要创建一个新的扩展了SurfaceView的类,并实现SurfaceHolder.Callback。

SurfaceHolder回调可以在底层的Surface被创建和销毁的时候通知View,并传递给它对SurfaceHolder对象的引用,其中包含了当前有效的Surface。

一个典型的Surface View设计模型包括一个由Thread所派生的类,它可以接收对当前的SurfaceHolder的引用,并独立地更新它。

3.  SurfaceHolder.Callback 回调接口的方法介绍
  surfaceChanged: 在Surface的大小发生改变时激发。
  surfaceCreated:   在创建Surface时激发
  surfaceDestroyed: 在销毁Surface时激发
  addCallback: 给SurfaceView添加一个回调函数
  lockCanvas: 锁定画布,绘图之前必须锁定画布才能得到当前画布对象。
  unlockCanvasAndPost: 开始绘图时锁定了画布,绘制完成之后解锁画布。
  removeCallback: 从SurfaceView 中移除回调函数。


  SurfaceView 和 View 的明显不同之处在于,继承SurfaceView  的视图可以另起一个线程或者 说在子线程中 更新视图 这与我上一篇的另外一个示例  android 自定义View类的简单使用 示例  (这个示例请点这里http://byandby.iteye.com/blog/821990)明显的一个区别就是 SurfaceView 的画图方法 是在 子线程中执行的 而 View类的那个示例 的画图方法 是在UI线程中执行的。 其实SurfaceView按道理应该违背了 android的 单线程模型 因为它在子线称中 画图 刷新界面 来更新UI 至于 它为什么可以这么做 我也不知道 有时间研究一下吧  可能它是一种特殊的视图吧。 还有要注意的一点就是 我们在绘图之前必须使用
lockCanvas 方法锁定画布,并得到画布,然后再画布上绘制;当绘制完成后,使用unlockCanvasAndPost 方法解锁画布,然后就显示到屏幕上。SurfaceView 类的事件处理规则和View一样。
    下面是这样一个例子 这个例子实现了一个不断变换颜色的圆形 并且实现了SurfaceView的事件处理。 我们可以通过模拟器的 上下键 来调节 这个圆 在屏幕中的位置。下面先看一下运行效果吧。



    GameSurfaceView 类
package xiaohang.zhimeng;

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

public class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{

	//控制循环
	boolean mbLoop = false;

	//定义SurfaceHolder对象
	SurfaceHolder mSurfaceHolder = null;
	int miCount = 0;
	int y =50;
	
	public GameSurfaceView(Context context) {
		super(context);
		//实例化SurfaceHolder
		mSurfaceHolder = this.getHolder();
		
		//添加回调 函数
		//注意这里这句 mSurfaceHolder.addCallback(this)这句执行完了之后 
		//马上就会回调 surfaceCreated方法了 然后开启线程 执行绘图方法这里这个执行顺序要搞清楚
		mSurfaceHolder.addCallback(this);
		this.setFocusable(true);
		mbLoop = true;
	}
	
	//在surface的大小发生改变时激发
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
	}
	
	//surface创建时激发 此方法在主线程总执行
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		//开启绘图线程
		new Thread(this).start();
	}
	
	//在surface销毁时激发
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		//停止循环
		mbLoop = false;
	}
	
	//绘图循环
	@Override
	public void run() {
		while (mbLoop){
			try {
				Thread.sleep(200);
			} catch (Exception e) {
				
			}
			//至于这里为什么同步这就像一块画布 你不能让两个人同时往上边画画
			synchronized( mSurfaceHolder ){
				Draw();
			}
		}
	}
	//绘图方法  注意这里是另起一个线程来执行绘图方法了不是在UI 线程了
	public void Draw(){
		//锁定画布,得到canvas 用SurfaceHolder对象的lockCanvas方法
		Canvas canvas = mSurfaceHolder.lockCanvas();
		if (mSurfaceHolder==null || canvas == null) {
			return;
		}
		if (miCount < 100) {
			miCount++;
		}else {
			miCount = 0;
		}
		//绘图
		Paint mPaint = new Paint();
		//给Paint对象加上抗锯齿标志
		//[url]http://tech.techweb.com.cn/thread-459611-1-1.html[/url] 详细说明可以看看这里 --->大家直接复制链接到 浏览器打开吧。
		mPaint.setAntiAlias(true);
		mPaint.setColor(Color.BLACK);
		//绘制矩形---清屏作用
		canvas.drawRect(0, 0, 320, 480, mPaint);
		switch (miCount % 4) {
		case 0:
			mPaint.setColor(Color.BLUE);
			break;
		case 1:
			mPaint.setColor(Color.GREEN);
			break;
		case 2:
			mPaint.setColor(Color.RED);
		case 3:
			mPaint.setColor(Color.YELLOW);
		default:
			mPaint.setColor(Color.WHITE);
			break;
		}
		//绘制矩形
		canvas.drawCircle((320 - 25) / 2, y, 50, mPaint);
		//绘制后解锁,绘制后必须解锁才能显示
		mSurfaceHolder.unlockCanvasAndPost(canvas);
	}
}


Activity01 类
package xiaohang.zhimeng;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;

public class Activity01 extends Activity {
	GameSurfaceView mGameSurfaceView;
	
	
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        //创建GameSurfaceView对象
        mGameSurfaceView = new GameSurfaceView(this);
        
        //设置显示GameSurfaceView视图
        setContentView(mGameSurfaceView);
    }
	
	//触笔事件 返回值为true 父视图不做处理以下返回值为true的都是不做处理的
	public boolean onTouchEvent(MotionEvent event){
		return true;
	}
	//按键按下事件  
	public boolean onKeyDown(int keyCode, KeyEvent event){
		return true;
	}
	//按键弹起事件
	public boolean onKeyUp(int keyCode, KeyEvent event){
		switch (keyCode) {
		//上方向键
		case KeyEvent.KEYCODE_DPAD_UP:
			mGameSurfaceView.y-=3;
			break;
		//下方向键
		case KeyEvent.KEYCODE_DPAD_DOWN:
			mGameSurfaceView.y+=3;
			break;
		}
		return false;
	}
	public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event){
		return true;
	}
}


  写完这个例子 我有些疑问
可不可以 在 类似这种 SurfaceView 上边放一些控件呢?
前边已经说了Surface是提供给需要直接画像素而不是使用窗体部件的应用使用的。 但是 我还是想知道 为什么 不能再Surface上边放 一个控件 比如 一个 button 或者 一个 textview 这里我们来拿button 举例子 比如我们想在 Surface上边放一个 button 这时 我们就需要 new一个 button 按钮了呗  在Acvity01 类中我们可以这样做 Button button = new Button(this);
但是 你new 完这个 button 你怎么把它 放倒 SurfaceView 这个视图上呢? 因为在Activity01这个类中我们是这样设置布局的  setContentView(mGameSurfaceView); 它的布局就是一个 SurfaceView 说白了也是一个View  这就相当于在一个视图上在放一个视图
这是放不了的 。
    这时候有人就想了 我们可以把Button 放在 GameSurfaceView 类中 这个想法真是聪明 太聪明了。 然后我们就到 GameSurfaceView类中 这样写 Button button = new Button(this); 你会惊奇的发现他报错了 。 为什么呢?  下面我把 android 中 Button的源码贴上来 大家 看看。。
@RemoteView
public class Button extends TextView {
    public Button(Context context) {
        this(context, null);
    }

    public Button(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.buttonStyle);
    }

    public Button(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
}

Button 这个类比较简单 就三个构造方法。 但是 每个 构造方法 都需要一个 Context 对象。
这一点大家显然都已经注意到了。 那为什么 我可以再 在继承Activity的类里边 new一个Button 而在 继承 SurfaceView的类中确不行呢。
我们分别来看一下  Activity01 类 和 GameSurfaceView类的继承关系


我想大家已经知道 为什么 SurfaceView 上边不可以放一些我们常用的控件了 也知道为什么我们可以再Activity类 里边可以 new Button 而在 SurfaceView 类里边却不行 因为我们的Activity类本身就是一个 Context对象。 而我们的 SurfaceView本身 不是 一个Context对象。 而我们要new 一个Button 怎么都得需要一个Context对象。 从这个角度其实就可以解释为什么 我们不能再SurfaceView上边放一些我们常用的控件了 Button TextView之类的。
  就写到这里。
源代码 附件。 测试平台 android 2.0
  • 大小: 21.3 KB
  • 大小: 21.5 KB
  • 大小: 22.6 KB
  • 大小: 23.7 KB
  • 大小: 23.6 KB
6
2
分享到:
评论
7 楼 Eson_Chow 2013-10-23  
6 楼 lengyueheiying 2011-11-11  
5 楼 zhaopian16 2010-12-20  
byandby 写道
   原来的示例 代码 有异常 因为Activity01类里边有一行代码没有注释掉  改过之后的代码已经重新上传。   


……这样啊?有个问题请教,我现在想用动画的形式作一个应用,所以应该使用surfaceView来刷出动画效果吧?但是后期可能要使用一个EditView来让用户输入一些文字在里面,这应该怎么实现?按照您说的,surfaceView不可以,那view能实现我的这个想法吗?
4 楼 byandby 2010-11-30  
   原来的示例 代码 有异常 因为Activity01类里边有一行代码没有注释掉  改过之后的代码已经重新上传。   
3 楼 byandby 2010-11-30  
   这个源码大家下载有错误吗? 可以反馈一下。
2 楼 a461519787 2010-11-25  
楼主 继续 努力,加油 多弄些 给力的文章 出来啊。。
1 楼 lovext 2010-11-25  
Great job! thanks!

相关推荐

    android之surfaceview学习示例

    在这个"android之surfaceview学习示例"中,我们将深入探讨SurfaceView的核心特性和使用方法。 首先,SurfaceView拥有自己的Surface对象,它位于窗口的最底层,直接与硬件交互,允许在主线程之外进行绘制操作,避免...

    在surfaceview上放置控件

    你可以通过查看这些文件,进一步理解如何在SurfaceView上添加和管理控件。 总的来说,结合SurfaceView和FrameLayout,开发者可以创建出既有高效图形渲染能力,又能提供交互性界面的应用。这在处理需要实时更新和...

    android surfaceview示例源码下载

    android中的surfaceview示例源码下载,Android SurfaceView在游戏开发中使用想当广泛,SurfaceView对于画面的控制有着更大的自由度,它不像View那样要用handler来更新,但是网上关于 SurfaceView使用这方面的参考...

    Android中SurfaceView截屏

    在Android开发中,`SurfaceView`是一个非常重要的视图组件,尤其在处理视频播放、游戏渲染等高性能图形操作时,它的优势在于拥有独立于主线程的渲染机制,能避免阻塞UI更新。然而,由于其特殊的性质,直接通过常规...

    Android SurfaceView使用Demo

    **Android SurfaceView 使用详解** `SurfaceView` 是 Android 系统提供的一种特殊的视图组件,它允许开发者在应用程序中创建高性能的图形界面,比如游戏、视频播放器等需要连续更新图像的应用。`SurfaceView` 提供...

    Android SurfaceView 实现图片缩放 滑动

    综上所述,通过结合SurfaceView、手势检测和矩阵变换,我们可以实现在Android应用中对图片的流畅缩放和滑动操作。然而,由于SurfaceView的特性,这个过程可能会比使用ImageView等其他组件更为复杂。因此,开发者需要...

    android中surfaceview控件的使用范例

    3. 如果不需要实时更新,可以使用SurfaceView的姐妹类TextureView,它提供了硬件加速的2D渲染,但可能消耗更多内存。 五、SurfaceView的范例——创建一个简单的动画 ```java class DrawingThread extends Thread {...

    android surfaceview 悬浮窗圆角 windowmanager

    要实现`SurfaceView`的圆角效果,一种常见的方法是使用自定义的`ViewGroup`来包裹`SurfaceView`,并在此`ViewGroup`上设置圆角。这通常涉及到对`onDraw()`方法的重写,通过`Canvas`进行裁剪或绘制圆形遮罩来达到圆角...

    android surfaceView 双缓冲

    android使用双缓冲辨析及surfaceview使用例子

    Android SurfaceView添加组件view不被组件覆盖.zip

    例如,可以使用`android:layout_marginTop`属性来让其他View在SurfaceView之上,但注意这可能会部分遮挡SurfaceView的内容。 另一种解决方案是使用`OverlayLayer`。Android提供了一个叫做`TextureView`的类,它也...

    Android下使用SurfaceView播放视频文件

    在Android平台上,SurfaceView是一种特殊的视图,常用于处理高性能的图形渲染,比如播放视频或者游戏画面。在视频播放场景中,SurfaceView提供了一个高效且低延迟的显示机制,能够将视频帧直接绘制到Surface上,减少...

    Android SurfaceView 实现实时显示摄像头视频

    `SurfaceView`是Android提供的一种用于高效显示多媒体数据的视图组件,尤其适合处理像视频流这样的实时数据。本篇文章将深入探讨如何利用`SurfaceView`实现实时显示摄像头视频。 首先,我们需要了解`SurfaceView`的...

    android之view和surfaceview用法示例汇总

    在Android开发中,View和SurfaceView是两种非常重要的视图组件,它们用于在屏幕上显示内容和处理用户交互。本文将详细解析View和SurfaceView的基本概念、用法以及它们之间的区别,通过实例代码来帮助理解。 **一、...

    Android SurfaceView添加组件view不被组件覆盖-IT计算机-毕业设计.zip

    这个压缩包中的源码示例很可能是为了展示如何在SurfaceView上添加其他组件,而这些组件不会覆盖或影响SurfaceView的显示。 首先,我们需要理解SurfaceView的工作原理。SurfaceView在窗口管理器中创建了一个单独的...

    android surfaceview自定义拍照 绘制头像轮廓

    这个项目"android surfaceview自定义拍照 绘制头像轮廓"是基于网上现有的示例代码进行了修改,用于实现一个自定义的拍照功能,并且在拍摄的照片上能够绘制出人像的轮廓。下面我们将深入探讨`SurfaceView`以及如何...

    android SurfaceView游戏框架

    在Android平台上开发游戏时,SurfaceView是一个至关重要的组件,它为高效、低延迟的图形渲染提供了可能。SurfaceView是Android系统提供的一种特殊视图,它有自己的独立绘制表面,与主线程分离,使得游戏或者视频这类...

    安卓Android源码——SurfaceView添加组件view不被组件覆盖.zip

    `Android SurfaceView添加组件view不被组件覆盖` 这个文件可能是示例代码或者详细教程,里面应该包含了如何将这些概念应用到实际项目中的具体步骤。 总的来说,处理 `SurfaceView` 与其他组件的层次关系是安卓开发...

    Android SurfaceView 多线程 滑块

    这可能涉及到使用Android Studio的调试工具,如Logcat用于日志输出,以及性能分析器(Profiler)来检测CPU、内存和GPU的使用情况。 总的来说,这个"Android SurfaceView 多线程 滑块"示例是一个很好的学习资源,它...

    Android圆形相机预览窗口,圆形SurfaceView

    要在SurfaceView上实现圆形预览,我们需要覆盖SurfaceView的默认矩形形状。这可以通过自定义一个继承自SurfaceView的类来实现,然后在该类中重写onDraw()方法。在onDraw()中,我们可以使用Canvas对象绘制一个圆形的...

Global site tag (gtag.js) - Google Analytics