1、View
View 看需要重写几个函数,分别是绘图函数onDraw ,按键按下函数 onKeyDown,按键抬起函数 onKeyUp,触屏函数onTouchEvent
其中绘图函数含有画笔paint和画布canvas
@SuppressLint("DrawAllocation")
public class MyView extends View {
private int tX=10 , tY=10;
public MyView (Context context){
super(context);
//给当前View设置焦点,其实就是告示系统,现在这个视图需要与用户交互,让系统来监听此视图
setFocusable(true);
}
protected void onDraw(Canvas canvas){
Paint paint =new Paint();
paint.setColor(Color.WHITE);
canvas.drawText("HI View", tX, tY, paint);
super.onDraw(canvas);
}
public boolean onKeyDown (int keyCode, KeyEvent event){
//KeyEvent 指的是按键的动作事件队列,此类还定义了很多静态常量键值
if(keyCode == KeyEvent.KEYCODE_DPAD_UP){
tY-=2;
}else if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
tY+=2;
}else if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
tX-=2;
}else if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
tX+=2;
}
//invalidate方法不能再当前线程中 循环 调用执行,而postInvalidate()函数可以在子线程中循环调用执行
//如果不在当前View创建线程循环重绘画布的话,则两种方式没有区别
invalidate();
//postInvalidate();
return super.onKeyDown(keyCode, event);
}
public boolean onKeyUp(int keyCode,KeyEvent event){
return super.onKeyUp(keyCode, event);
}
public boolean onToucnEvent(MotionEvent event){
int x=(int) event.getX();
int y=(int) event.getY();
//玩家点击屏幕的动作
if(event.getAction()==MotionEvent.ACTION_DOWN){
tX=x;
tY=y;
//玩家手指抬起离开屏幕的动作
}else if(event.getAction()==MotionEvent.ACTION_MOVE){
tX=x;
tY=y;
//玩家手指在屏幕上移动的动作
}else if(event.getAction()==MotionEvent.ACTION_UP){
tX=x;
tY=y;
}
invalidate();
return super.onTouchEvent(event);
}
}
在MainActivity让屏幕显示MyView类(在这里去掉标题栏和状态栏)
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new MyView(this));
}
}
2、 SurfaceView
(0)SurfaceView是View的子类
(1)SurfaceHolder类提供控制SurfaceView的大小、格式等,并且主要用于监听SurfaceView的状态。
(2)SurfaceView只是保存当前视图的像素数据
(3)使用SurfaceHolder的lockCanvas()函数不仅是获取canvas,同时还对获取的 Canvas画布进行加锁,防止绘制的过程中被修改和摧毁
(4)SurfaceHolder对SurfaceView的状态进行监听需要使用android.view.SurfaceHolder.Callback接口:此接口需要重写三个函数
当SurfaceView被创建完成后响应的函数 public void surfaceCreated(SurfaceHolder holder){}
当SurfaceView状态发生改变时响应的函数 pubic void surfaceChanged (SurfaceHolder ,int format , int width ,int height){}
当SurfaceView状态摧毁时响应的函数 public void surfaceDestroyed(SurfaceHolder ){}
public class MySurfaceView extends SurfaceView implements Callback{
private SurfaceHolder sfh;
private Paint paint;
public MySurfaceView (Context context){
super(context);
sfh = this.getHolder();
//为SurfaceView添加状态监听
sfh.addCallback(this);
paint = new Paint();
paint.setColor(Color.WHITE);
}
public void surfaceCreated(SurfaceHolder holder){
myDraw();
}
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
}
public void surfaceDestroyed(SurfaceHolder holder){
}
//自定义绘图函数
public void myDraw(){
Canvas canvas = sfh.lockCanvas();
canvas.drawText("HI SurfaceView", 10, 10, paint);
sfh.unlockCanvasAndPost(canvas);
}
}
刷屏的方式有几种:
(1)每次绘图之前,绘制一个等同于屏幕大小的图形或者背景图片覆盖在画布之上
(2)每次绘图之前,在画布上填充一种颜色(肯定不是修改画笔颜色嘛),可以指定颜色也可以用RGB表示
修改后的Draw函数如下:
public void myDrawAfterModify1(){
Canvas canvas =sfh.lockCanvas();
canvas.drawRect(0, 0, this.getHeight() ,this.getWidth(), paint);
canvas.drawText("HI SurfaceView", tX, tY, paint);
sfh.unlockCanvasAndPost(canvas);
}
public void myDrawAfterModify2(){
Canvas canvas =sfh.lockCanvas();
canvas.drawColor(Color.BLACK);
canvas.drawText("HI SurfaceView", tX, tY, paint);
sfh.unlockCanvasAndPost(canvas);
}
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new MySurfaceView(this));
}
}
3、SurfaceView视图添加线程
(1)线程的初始化和线程的启动都写在视图的SurfaceCreated创建函数当中,并且将线程标识位在视图摧毁时将其值改变为false
(2)Bcak键之后:
surfaceDestroyed->构造函数->surfaceCreated->surfaceChanged
Home键之后
surfaceDestroyed->surfaceCreated->surfaceChanged
也就是说按键Back之后,surfaceView会被重新加载
(3)获取视图的宽和高
一定要在视图创建之后才可获取到
(4)绘图函数try一下
因为当SurfaceView不可编辑或者尚未创建时,调用lockCanvas()函数会返回NULL
(5)提交画布必须放在finally下
绘图的时候可能会出现不可预知的BUG,在try下不会崩溃,但是在提交画布之前出错的话,那么解锁提交画布函数则无法被执行到,这样会导致下次通过lockCanvas来获取
Canvas时抛出异常
(6)刷帧时间尽可能保持一致
public class MySurfaceView extends SurfaceView implements Callback ,Runnable{
private SurfaceHolder sfh;
private Paint paint;
private int tX=10, tY=10;
//生命一个线程
private Thread th;
//线程消亡的标志位
private boolean flag;
private Canvas canvas;
//声明屏幕的宽高
private int screenW ,screenH;
public MySurfaceView (Context context){
super(context);
sfh = this.getHolder();
//为SurfaceView添加状态监听
sfh.addCallback(this);
paint = new Paint();
paint.setColor(Color.WHITE);
setFocusable(true);
}
public void surfaceCreated(SurfaceHolder holder){
screenW =this.getWidth();
screenH =this.getHeight();
flag =true;
th = new Thread(this);
th.start();
}
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
}
public void surfaceDestroyed(SurfaceHolder holder){
flag=false;
}
//自定义绘图函数
public void myDraw(){
try{
canvas = sfh.lockCanvas();
if(canvas!=null){
//canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), paint);
canvas.drawRGB(0, 0, 0);
canvas.drawText("HI GameSurfaceView", tX, tY, paint);
}
}catch(Exception e){
}finally{
if(canvas!=null)
sfh.unlockCanvasAndPost(canvas);
}
}
public boolean onTouchEvent(MotionEvent event){
tX=(int) event.getX();
tY=(int) event.getY();
myDraw();
return true;
}
public boolean onKeyDown(int keyCode,KeyEvent event){
return super.onKeyDown(keyCode, event);
}
//游戏逻辑
private void logic(){}
public 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){
e.printStackTrace();
}
}
}
}