Android中SurfaceView,是不使用游戏引擎,开发一款游戏的经常使用view控件。java
SurfaceView经常被用来显示那些更新速度比较快(这个速度一般人眼没法识别)的图像,经常被用来显示照相机的当前效果,视频的播放,游戏界面的播放。canvas
SurfaceView的建立:缓存
继承SurfaceView就可使用构造方法建立了。dom
所要重新写的方法也只不过一个构造方法,这里使用的构造经常有两种,一种使用只有一个参数的构造方法,参数为context,若是使用这样的构造方法,则建立SurfaceView的Activity不能加载layout文件夹中的xml文件,只能加载new出来的view如ide
public class GameMainActivity extends Activity { public static GameView Game; public static AssetManager assets; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Assets.mContentResolver=getContentResolver(); Game=new GameView(GameMainActivity.this); setContentView(Game); assets=getAssets(); } }
若是使用两个参数的构造方法:布局
Context context, AttributeSet attrs
则能够将本身View类当作Activity布局文件中的一个空间,当布局文件显示时会自动调用这个构造方法,第二参数用于返回相应的指令给View。
可是这里建议使用第一个方法构造,由于在游戏中的界面跳转与外部Activity的跳转逻辑彻底不一样,因此在布局文件中加载会有必定的弊端。可是好处是这样可使用Android封装好的控件(如button)。this
SurfaceView有一个特色:spa
他并非当Activity建立 就会能够调用的,里面的那些控件,并非真的控件,当Activity建立完成就可使用了,而是当SurfaceView建立,并出如今屏幕上以后才能够开始绘画(即伪控件的加载)。线程
这时就须要一个监听器监听SurfaceView的建立,改变和销毁。code
使用监听器
SurfaceHolder.Callback
这里要实现这个接口,重写其中的三个主要方法:
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) public void surfaceDestroyed(SurfaceHolder holder) 这三个方法表明了SurfaceView生命周期,注意只有在这三个声明周期中才能够进行其中的操做,在Activity中的操做要与之区分。 当建立时自动调用createed和changed方法,在home键,back键返回时调用destroyed方法,可是注意home键返回再回来依次调用created方法,和changed方法,可是back键返回再回来就会调用构造方法和created方法,changed方法。设置监听时要先初始化SurfaceView的管家类SurfaceHolder,经过在View中调用父类SurfaceView的方法getholder就能够简单的获取管家。
public class MyView extends SurfaceView implements Runnable,SurfaceHolder.Callback,View.OnTouchListener { Context main; SurfaceHolder holder;//主holder Canvas canvas;//主画布 Paint p; Thread t; Bitmap buffer=null;//二级缓存 Path mpath;//触控中的轨迹 float startX; float startY; Rect window; Rect bufferRect; boolean run=false; public MyView(Context context) { super(context); init(context); setOnTouchListener(this); } private void init(Context context){ holder=getHolder(); holder.addCallback(this);//勿忘addcallback this.main=context; p=new Paint(); p.setAntiAlias(true);//消除锯齿 p.setStyle(Paint.Style.STROKE);//设置画笔风格 p.setAlpha(255);//画笔的不透明度 p.setStrokeWidth((float)2);//设置笔触宽度 p.setColor(Color.WHITE); mpath=new Path(); buffer= Bitmap.createBitmap(1440,2256, Bitmap.Config.ARGB_8888);//很重要建立二级缓存的必要方法 t=new Thread(this); } @Override public void run() { while(run){ canvas=holder.lockCanvas(); window=canvas.getClipBounds(); Canvas c=new Canvas(buffer); c.drawRect(window,p); p.setColor(Color.rgb(new Random().nextInt(255),new Random().nextInt(255),new Random().nextInt(255))); c.drawPath(mpath,p); bufferRect=new Rect(0,0,buffer.getWidth(),buffer.getHeight()); canvas.drawBitmap(buffer,bufferRect,window,new Paint()); holder.unlockCanvasAndPost(canvas); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void surfaceCreated(SurfaceHolder holder) { run=true; Log.i("Created", "surfaceCreated: "); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.i("Changed", "surfaceChanged: "); t=new Thread(this); t.start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { run=false; try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } Log.i("Destroyed", "surfaceDestroyed: "); } private void onTouchDown(MotionEvent event){ startX=event.getX(); startY=event.getY(); mpath.reset(); mpath.moveTo(startX,startY); } private void onTouchMove(MotionEvent event){ float touchX=event.getX(); float touchY=event.getY(); float dx=Math.abs(touchX-startX);//移动的距离 float dy =Math.abs(touchY-startX);//移动的距离 if(dx>3||dy>3){ float cX=(touchX+startX)/2; float cY=(touchY+startY)/2; mpath.quadTo(startX, startY, cX, cY);//绘制贝塞尔曲线 startX=touchX; startY=touchY;//改变开始绘制的点 }//这里巧妙地进行筛选过于短的移动 } @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: this.onTouchDown(event); break; case MotionEvent.ACTION_MOVE: this.onTouchMove(event); break; case MotionEvent.ACTION_UP: break; } return true; } }