您的位置:首页 > 移动开发 > Android开发

android中的SurfaceView的理解

2014-12-02 21:56 218 查看
1.SurfaceView是继承View的派生类(public class SurfaceView extends View {...}),这个View里内嵌了一个专门用于绘制的Surface,这个可以类似的理解成为一个在View里的Canvas。你可以控制这个Surface的格式和尺寸。Surfaceview类则控制这个Surface在屏幕上的正确位置。

2.在一般情况下,应用程序的View都是在相同的GUI线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如按钮单击或者文本输入)。

对于一个View的onDraw()方法,不能够满足将其移动到后台线程中去。因为从后台线程修改一个GUI元素会被显式地禁止的,当需要快速地更新View的UI,或者当前渲染代码阻塞GUI线程的时间过长的时候,SurfaceView就是解决上述问题的最佳选择。SurfaceView封装了一个Surface对象,而不是Canvas。这一点很重要,因为Surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如使用3D图形,创建游戏,或者实时预览摄像头,这一点特别有用。

3.如何使用使用一个SurfaceView,首先继承SurfaceView并实现SurfaceHolder.Callback接口。因为使用SurfaceView
有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始。Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。

需要重写的方法

(1)public void surfaceChanged(SurfaceHolder holder,int
format,int width,int height){}

//在surface的大小发生改变时激发

(2)public void surfaceCreated(SurfaceHolder holder){}

//在创建时激发,一般在这里调用画图的线程。

(3)public void surfaceDestroyed(SurfaceHolder holder) {}

//销毁时激发,一般在这里将画图的线程停止、释放。

4.下面举个在网上的一个被我改版的小球运动的例子

a.MyPinBallSurfaceView类
public class MyPinBallSurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{

//桌面的宽度
private int tableWidth;
//桌面的高度
private int tableHeight;
//球拍的垂直位置
private int racketY;
//定义球拍的高度和宽度
private final int RACKET_HEIGHT = 20;
private final int RACKET_WIDTH = 70;
//小球的大小
private final int BALL_SIZE = 12;
//小球纵向的运行速度
private int ySpeed = 10;
Random rand = new Random();
//返回一个-0.5~0.5比率,用于控制小球的运行方向
private double xyRate = rand.nextDouble() - 0.5;
//小球横向的运行速度
private int xSpeed = (int)(ySpeed * xyRate * 2);
//ballX和ballY代表小球坐标
private int ballX = rand.nextInt(200) + 20;
private int ballY = rand.nextInt(10) + 20;
//racketX代表球拍的水平位置
private int racketX = rand.nextInt(200);
//游戏是否结束的旗标
private boolean isLose = false;

private SurfaceHolder mSurfaceHolder;

private boolean flag;//控制绘图结束的标示
private Thread mThread;
float x=0;

public MyPinBallSurfaceView(Context context){
super(context);
mSurfaceHolder=this.getHolder();
mSurfaceHolder.addCallback(this);
//在这里获取屏幕的宽高是为0的。在网上看到说是在这里布局还没有绘制出来获取到的宽高就为0。
//		Rect mRect=mSurfaceHolder.getSurfaceFrame();
//		mRect.width();
//		mRect.height();
}

public MyPinBallSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
tableWidth=getWidth();
tableHeight=getHeight();
racketY=tableHeight-50;
flag=true;
start();
mThread=new Thread(this);
mThread.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
flag=false;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
x=event.getX();
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
//点击的位置在挡板的位置右侧则向左移
if(x<=racketX){
if(racketX>0){
racketX-=10;
}
}
//这里判断点击的位置在挡板的右边则向右移
if(x>=(racketX+RACKET_WIDTH)){
if(racketX<tableWidth-RACKET_WIDTH){
racketX+=10;
}
}
break;
}
return true;
}

@Override
public void run() {
while(flag){
myDraw();
}
}

public void start(){
final Timer mTimer=new Timer();
mTimer.schedule(new TimerTask() {

@Override
public void run() {
//如果小球碰到左边边框
if(ballX <= 0 || ballX >= tableWidth - BALL_SIZE){
xSpeed = -xSpeed;
}
//如果小球高度超出了球拍位置,且横向不在球拍范围之内,游戏结束
if(ballY >= racketY - BALL_SIZE && (ballX < racketX || ballX > racketX + RACKET_WIDTH)){
mTimer.cancel();
//设置游戏是否结束的旗标为true
isLose = true;
}
//如果小球位于球拍之内,且到达球拍位置,小球反弹
else if(ballY <= 0 || (ballY > racketY - BALL_SIZE && ballX > racketX && ballX <= racketX + RACKET_WIDTH)){
ySpeed = -ySpeed;
}
//小球坐标增加
ballY += ySpeed;
ballX += xSpeed;
}
},0,700);
}

/**
* 游戏绘图自定义的绘图方法
*/
public void myDraw(){
Canvas mCanvas=null;
try{
mCanvas=mSurfaceHolder.lockCanvas();
if(mCanvas!=null){
mCanvas.drawColor(Color.TRANSPARENT,Mode.CLEAR);
Paint mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.FILL);
if(isLose){
mPaint.setColor(Color.RED);
mCanvas.drawText("游戏结束!",150,200,mPaint);
}else{
mPaint.setColor(Color.rgb(240, 240, 80));
mCanvas.drawCircle(ballX,ballY,BALL_SIZE,mPaint);
//设置颜色,并绘制挡板
mPaint.setColor(Color.rgb(80, 80, 200));
mCanvas.drawRect(racketX,racketY, racketX + RACKET_WIDTH,
racketY+RACKET_HEIGHT,mPaint);
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(mCanvas!=null){
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
b.MainActivity类

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new MyPinBallSurfaceView(this));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: