zoukankan      html  css  js  c++  java
  • 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 " + 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 " + 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);
            }
    }
    


  • 相关阅读:
    Java的注释,标识符,标识符的命名规范
    Java入门程序(Java的开发流程)
    EasyMock使用总结
    【转载】 Java并发编程:深入剖析ThreadLocal
    java.util.Stack类中的peek()方法
    Jquery和Ajax
    关于HTTP协议及SOCKET通信
    (转载)session token机制
    TCP/IP知识总结(TCP/IP协议族读书笔记四)
    TCP/IP知识总结(TCP/IP协议族读书笔记三)
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3365964.html
Copyright © 2011-2022 走看看