首页 > 代码库 > Android自定义组件系列【12】——非UI线程绘图SurfaceView

Android自定义组件系列【12】——非UI线程绘图SurfaceView

一、SurfaceView的介绍

在前面我们已经会自定义View,使用canvas绘图,但是View的绘图机制存在一些缺陷。

1、View缺乏双缓冲机制。

2、程序必须重绘整个View上显示的图片,比较耗资源。

3、非UI线程无法更新View组件,所以会占用主线程资源,当需要在主线程中处理逻辑的时候会很慢。

在Android中为我们提供了一个SurfaceView来替代View实现绘制图形,一般在游戏绘图方面应用较广,所以如果是比较复杂的绘图建议使用SurfaceView.

二、SurfaceView的绘图机制

SurfaceView一般会与SurfaceHolder结合使用,SurfaceHolder用于与之关联的SurfaceView上绘图,调用SurfaceView的getHolder()方法可获取SurfaceView关联的SurfaceHolder.
SurfaceHolder提供了lockCanvas和lockCanvas(Rect dirty)来锁定绘图区域,并获取到该区域的画布(Canvas)我们通过该画布就可以进行图形的绘制了。

三、SurfaceView使用实例

1、一个简单的使用(绘制在UI线程)
package com.test.surfaceview;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnTouchListener;

import com.example.testsurfaceview.R;

public class MainActivity extends Activity{
	
	private SurfaceHolder holder;
	private Paint paint;
	private Rect rect;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		paint = new Paint();
		rect = new Rect();
		
		SurfaceView surface = (SurfaceView)findViewById(R.id.show);
		holder = surface.getHolder();
		
		//由系统毁掉的三个函数
		holder.addCallback(new SurfaceHolder.Callback() {
			
			@Override
			public void surfaceDestroyed(SurfaceHolder holder) {
			}
			
			@Override
			public void surfaceCreated(SurfaceHolder holder) {
				Canvas canvas = holder.lockCanvas();
				Bitmap bitmap = BitmapFactory.decodeResource(
						MainActivity.this.getResources(), R.drawable.ic_launcher);
				canvas.drawBitmap(bitmap, 0, 0, null);
				holder.unlockCanvasAndPost(canvas);
			}
			
			@Override
			public void surfaceChanged(SurfaceHolder holder, int format, int width,
					int height) {
			}
		});
		
		//绑定事件监听
		surface.setOnTouchListener(new OnTouchListener() {
			
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if(event.getAction() == MotionEvent.ACTION_DOWN){
					int cx = (int)event.getX();
					int cy = (int)event.getY();
					
					rect.set(cx - 50, cy - 50, cx + 50, cy + 50);
					//锁定一个固定区域并锁定
					Canvas canvas = holder.lockCanvas(rect);
					//保存画布当前状态
					canvas.save();
					//旋转画布
					canvas.rotate(30, cx, cy);
					paint.setColor(Color.RED);
					//绘制方块
					canvas.drawRect(cx - 40, cy - 40, cx, cy, paint);
					//恢复画布
					canvas.restore();
					paint.setColor(Color.GREEN);
					//绘制方块
					canvas.drawRect(cx, cy, cx + 40, cy + 40, paint);
					//绘制完成,释放画布,提交修改
					holder.unlockCanvasAndPost(canvas);
				}
				return false;
			}
		});
	}
}
2、在非UI线程中绘制
package com.test.surfaceview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.example.testsurfaceview.R;

/**
 * 阳光小强 http://blog.csdn.net/dawanganban
 * 
 * @author Administrator
 * 
 */
public class MySurfaceView extends SurfaceView {

	private Context context;
	private Rect rect;
	private Paint paint;


	private AppStartDrawView appStartDrawView;

	public MySurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		rect = new Rect();
		paint = new Paint();
		appStartDrawView = new AppStartDrawView();
		this.getHolder().addCallback(appStartDrawView);
	}

	/**
	 * 停止动画
	 */
	public void stopAnim() {
		appStartDrawView.cancel(true);
	}

	private class AppStartDrawView extends AsyncTask<Void, Integer, Void> implements SurfaceHolder.Callback {
		private boolean isStarted = false;
		private SurfaceHolder holder;

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			this.holder = holder;
			
			//绘制一个图片
			Canvas canvas = holder.lockCanvas();
			Bitmap bitmap = BitmapFactory.decodeResource(
					context.getResources(), R.drawable.ic_launcher);
			canvas.drawBitmap(bitmap, 0, 0, null);
			holder.unlockCanvasAndPost(canvas);
			
			if (!isStarted) {
				this.execute();
				isStarted = true;
			}
		}

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

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

		@Override
		protected Void doInBackground(Void... params) {
			int cx = 0;
			int cy = 0;
			while(!isCancelled()){
				//绘制动画
				//TODO .....
				rect.set(cx - 50, cy - 50, cx + 50, cy + 50);
				//锁定一个固定区域并锁定
				Canvas canvas = holder.lockCanvas(rect);
				//保存画布当前状态
				canvas.save();
				//旋转画布
				canvas.rotate(30, cx, cy);
				paint.setColor(Color.RED);
				//绘制方块
				canvas.drawRect(cx - 40, cy - 40, cx, cy, paint);
				//恢复画布
				canvas.restore();
				paint.setColor(Color.GREEN);
				//绘制方块
				canvas.drawRect(cx, cy, cx + 40, cy + 40, paint);
				//绘制完成,释放画布,提交修改
				holder.unlockCanvasAndPost(canvas);
				
				//TODO ....
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				cx += 60;
				cy += 60;
				
				if(cx  >= 400){
					stopAnim();
				}
			}
			return null;
		}

	}
}

Android自定义组件系列【12】——非UI线程绘图SurfaceView