Android 画图类View与SurfaceView之学习

在开发游戏开发中,android相应的提供了几个重要的模块:

1、显示界面的视图:  Android 提供 View 和 SurfaceView 

2、控制游戏整体结构: android 提供 Activity 

3、逻辑控制类:专门用于处理游戏的逻辑计算

4、处理游戏界面与用户交互事件 : 利用 View 类提供的 onKeyDown onKeyUp onTounchEvent等方法


我们这里简单熟悉一下如何在视图上画东西。


1、View 类: android.view.View 

View 是Android中的一个超类,这个类几乎包含了所有的屏幕类型。每一个View都有一个用于绘画的画布,这个画布 可以进行任何扩展。

任何一个View类都只需要重写onDraw方法来实现界面显示,任何一个View都只需要重写 OnDraw 方法来实现界面显示,自定义的视图可以是复杂的3D实现,也可以是非常简单的文本或位图。


Android 中有个重要的东东: Android UI 线程 

在这里 http://blog.csdn.net/andyhuabing/article/details/11921887 有对其简要精典的介绍及注意点,这里就不再重复说明了。


这里来个简单例子说明一下View的用法,利用线程变更显示颜色,通过上下左右移动矩形


TestView.java 类如下:

 

package com.example.testondraw;



import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.view.View;



/**

 * View 是Android中的一个超类,这个类几乎包含了所有的屏幕类型。每一个View都有一个用于绘画的画布,这个画布 可以进行任何扩展。

 * 

 * 任何一个View类都只需要重写onDraw方法来实现界面显示。

 * 

 */

public class TestView extends View {

	int miCount = 0;

	int x = 10, y = 10;



	public TestView(Context context) {

		super(context);

	}



	@Override

	protected void onDraw(Canvas canvas) {

		if (miCount < 100)

		{

			miCount++;

		}

		else 

		{

			miCount = 0;

		}

		//绘图

		Paint mPaint = new Paint();   

        switch (miCount%4)

		{

		case 0:

			mPaint.setColor(Color.BLUE);  	

			break;

		case 1:

			mPaint.setColor(Color.GREEN);  	

			break;

		case 2:

			mPaint.setColor(Color.RED);

			break;

		case 3:

			mPaint.setColor(Color.YELLOW);

			break;

		default:

			mPaint.setColor(Color.WHITE);

			break;

		}

		// 绘制矩形

		canvas.drawRect(x, y, x + 120, y + 80, mPaint);

	}

}


如何在 Acitivty 使用呢?示例代码如下:

 

 

package com.example.testondraw;



import java.util.List;



import android.app.Activity;

import android.app.ActivityManager;

import android.content.Context;

import android.graphics.Bitmap;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.util.DisplayMetrics;

import android.util.Log;

import android.view.KeyEvent;

import android.view.Menu;



public class MainActivity extends Activity {

	static final String TAG = "MainActivity";

	private TestView mTestView = null;

	private TestSurfaceView mTestSurfaceView = null;

	private int mWidth = 0, mHeight = 0;

	private MyHandler mHandler = new MyHandler();



	@Override

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);



		initView();



		startTestView();

		

		// setContentView(R.layout.main);

	}



	void initView() {

		// 使用自定义的View

		mTestView = new TestView(this);

		setContentView(mTestView);

	

		DisplayMetrics dm = new DisplayMetrics();

		getWindowManager().getDefaultDisplay().getMetrics(dm);

		mWidth = dm.widthPixels;

		mHeight = dm.heightPixels;

		Log.i(TAG, "Display Metrics width:" + mWidth + " mHeight:" + mHeight);

	}



	@Override

	public boolean onCreateOptionsMenu(Menu menu) {

		getMenuInflater().inflate(R.menu.main, menu);

		return true;

	}



	void startTestView() {

		Thread th = new Thread(new Runnable() {



			@Override

			public void run() {

				while (!Thread.currentThread().isInterrupted()) {

					// 使用postInvalidate可以直接在线程中更新界面

//					mTestView.postInvalidate();

					

					// 使用发消息给UI线程

					Message msg = Message.obtain();

					msg.what = 1;

					mHandler.sendMessage(msg);



					try {

						Thread.sleep(100);

					} catch (InterruptedException e) {

						Thread.currentThread().interrupt();

					}

				}

			}

		});

		th.start();

	}



	class MyHandler extends Handler {

		@Override

		public void handleMessage(Message msg) {

			switch (msg.what) {

			case 1:

				mTestView.invalidate();

				break;

			default:

				break;

			}

			super.handleMessage(msg);

		}

	}



	public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {

		switch (keyCode) {

		case KeyEvent.KEYCODE_DPAD_DOWN:

			if (mTestView.y >= mHeight)

				mTestView.y = 0;

			mTestView.y += 10;

			break;

		case KeyEvent.KEYCODE_DPAD_UP:

			if (mTestView.y <= 0)

				mTestView.y = mHeight;

			mTestView.y -= 10;

			break;

		case KeyEvent.KEYCODE_DPAD_LEFT:

			if (mTestView.x <= 0)

				mTestView.x = mWidth;

			mTestView.x -= 10;

			break;

		case KeyEvent.KEYCODE_DPAD_RIGHT:

			if (mTestView.x >= mWidth)

				mTestView.x = 0;

			mTestView.x += 10;

			break;

		}

		return false;

	};

}

 


2、SurfaceView  android.view.SurfaceView

当执行效率有要求很高时,View类就无法满足需求。必须使用 SurfaceView 类 -- 利用双缓冲技术


使用SurfaceView提供给需要直接画像素而不是使用画窗体部件的应用使用。

而每个Surface创建一个Canvas对象,用来管理View在Surface上的绘画操作。


简要说明一下具体的方法及使用:

SurfaceHolder 对象需要通过 getHolder() 获取

在 Layout 上摆一个 SurfaceView 组件:

mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView1);
SurfaceHolder holder = mSurfaceView.getHolder();


对于SurfaceView 的创建,销毁及变更

@SuppressWarnings("unused")
private SurfaceHolder.Callback mSurfaceCbk = new SurfaceHolder.Callback() {


@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {    // 在Surface 大小发生变更时触发
// TODO Auto-generated method stub

}


@Override
public void surfaceCreated(SurfaceHolder holder) { // 在创建 Surface 时触发
// TODO Auto-generated method stub

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) { // 在销毁 Surface 时触发
// TODO Auto-generated method stub

}

};


添加及删除 SurfaceView 的回调函数:

display.addCallback(mSurfaceCbk);

display.removeCallback(mSurfaceCbk);


Canvas 的使用:

lockCanvas  锁定画布,绘图之前必须锁定画布才能得到当前画布对象

unlockCanvasAndPost 开始绘制时锁定画布,绘制完成之后解锁画布


下面例子是绘制一个不断变换颜色的圆,并实现 SurfaceView 的事件处理

TestSurfaceView.java 代码:

 

package com.example.testondraw;



import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.view.SurfaceHolder;

import android.view.SurfaceView;



/**

 * 使用SurfaceView提供给需要直接画像素而不是使用画窗体部件的应用使用。

 * 而每个Surface创建一个Canvas对象,用来管理View在Surface上的绘画操作。

 */

public class TestSurfaceView extends SurfaceView implements

		SurfaceHolder.Callback {

	// 控制循环

	private boolean mbLoop = false;



	// 定义SurfaceHolder对象

	private SurfaceHolder mSurfaceHolder = null;

	private int miCount = 0;

	public int x = 50, y = 50;

	private int mWidth = 1280,mHeight = 720;

	private Bitmap mBitmap = null;

	

	public TestSurfaceView(Context context) {

		super(context);



		// 实例化SurfaceHolder

		mSurfaceHolder = this.getHolder();



		// 添加回调

		mSurfaceHolder.addCallback(this);

		this.setFocusable(true);

	}



	public void setDisplayWH(int w, int h) {

		mWidth = w;

		mHeight = h;

	}



	public void setBitmap(Bitmap bitmap) {

		this.mBitmap = bitmap;

	}



	@Override

	public void surfaceChanged(SurfaceHolder holder, int format, int width,

			int height) {

		// TODO Auto-generated method stub

		

	}



	@Override

	public void surfaceCreated(SurfaceHolder holder) {

		mbLoop = true;



		Thread th = new Thread(new Runnable() {



			@Override

			public void run() {

				while (mbLoop){

					try {

						Thread.sleep(200);

					} catch (InterruptedException e) {

						e.printStackTrace();

					}



					synchronized( mSurfaceHolder ){

						drawBitmap();

						DrawData();

					}

				}

			}

		});

		th.start();

	}



	@Override

	public void surfaceDestroyed(SurfaceHolder holder) {

		mbLoop = false;

	}



	private void drawBitmap() {

		// 锁定画布,得到canvas

		if (mSurfaceHolder == null || this.mBitmap == null)

			return;



		Canvas canvas = mSurfaceHolder.lockCanvas();

		if (canvas == null) {

			return;

		}



		// 绘图

		Paint paint = new Paint();

		paint.setAntiAlias(true);

		paint.setColor(Color.BLUE);



		canvas.drawBitmap(this.mBitmap, 0, 0, paint);



		// 绘制后解锁,绘制后必须解锁才能显示

		mSurfaceHolder.unlockCanvasAndPost(canvas);

	}



	// 绘图方法

	private void DrawData() {

		if (mSurfaceHolder == null)

			return;



		// 锁定画布,得到canvas

		Canvas canvas = mSurfaceHolder.lockCanvas();

		if (canvas == null) {

			return;

		}



		if (miCount < 100) {

			miCount++;

		} else {

			miCount = 0;

		}



		// 绘图

		Paint mPaint = new Paint();

		mPaint.setAntiAlias(true);

		mPaint.setColor(Color.BLACK);



		// 绘制矩形--清屏作用

		canvas.drawRect(0, 0, mWidth, mHeight, mPaint);

		

		switch (miCount % 4) {

		case 0:

			mPaint.setColor(Color.BLUE);

			break;

		case 1:

			mPaint.setColor(Color.GREEN);

			break;

		case 2:

			mPaint.setColor(Color.RED);

			break;

		case 3:

			mPaint.setColor(Color.YELLOW);

			break;

		default:

			mPaint.setColor(Color.WHITE);

			break;

		}



		// 绘制矩形--

		canvas.drawCircle(x, y, 50, mPaint);

		

		// 绘制后解锁,绘制后必须解锁才能显示

		mSurfaceHolder.unlockCanvasAndPost(canvas);

	}

}


测试使用例子:

 


 

package com.example.testondraw;



import java.util.List;



import android.app.Activity;

import android.app.ActivityManager;

import android.content.Context;

import android.graphics.Bitmap;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.util.DisplayMetrics;

import android.util.Log;

import android.view.KeyEvent;

import android.view.Menu;

import android.view.SurfaceHolder;

import android.view.SurfaceView;



public class MainActivity extends Activity {

	static final String TAG = "MainActivity";

	private TestSurfaceView mTestSurfaceView = null;

	private int mWidth = 0, mHeight = 0;



	@Override

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);



		initView();



		startTestSurfaceView();

		

		// setContentView(R.layout.main);

	}



	void initView() {

		// 使用自定义的View

		mTestSurfaceView = new TestSurfaceView(this);

		setContentView(mTestSurfaceView);		



		DisplayMetrics dm = new DisplayMetrics();

		getWindowManager().getDefaultDisplay().getMetrics(dm);

		mWidth = dm.widthPixels;

		mHeight = dm.heightPixels;

		Log.i(TAG, "Display Metrics width:" + mWidth + " mHeight:" + mHeight);

	}



	@Override

	public boolean onCreateOptionsMenu(Menu menu) {

		getMenuInflater().inflate(R.menu.main, menu);

		return true;

	}



	public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {

		switch (keyCode) {

		case KeyEvent.KEYCODE_DPAD_DOWN:

			if (mTestSurfaceView.y >= mHeight)

				mTestSurfaceView.y = 0;

			mTestSurfaceView.y += 10;

			break;

		case KeyEvent.KEYCODE_DPAD_UP:

			if (mTestSurfaceView.y <= 0)

				mTestSurfaceView.y = mHeight;

			mTestSurfaceView.y -= 10;

			break;

		case KeyEvent.KEYCODE_DPAD_LEFT:

			if (mTestSurfaceView.x <= 0)

				mTestSurfaceView.x = mWidth;

			mTestSurfaceView.x -= 10;

			break;

		case KeyEvent.KEYCODE_DPAD_RIGHT:

			if (mTestSurfaceView.x >= mWidth)

				mTestSurfaceView.x = 0;

			mTestSurfaceView.x += 10;

			break;

		case KeyEvent.KEYCODE_BACK:

			this.finish();

			break;

		}

		return false;

	};



	void startTestSurfaceView() {

		mTestSurfaceView.setDisplayWH(mWidth, mHeight);

        }

}


 

 

你可能感兴趣的:(SurfaceView)