如何实现Android SurfaceView

SurfaceView是View的继承结构中一个比较特殊的子类,它的作用是提供一个第二线程来完成图形的绘制。因此应用程序不需要等待View的图形绘制,第二线程会异步完成图形的绘制。

SurfaceView实现的步骤:

  1. 继续SurfaceView并实现SurfaceHolder.Callback接口,该接口提供了SurfaceView创建、属性发生变化、销毁的时间点,那么你可以在适当的时间点完成具体的工作。
  2. 在SurfaceView初始化的时候调用SurfaceView.getHolder()方法获取一个SurfaceHolder,SurfaceHolder用于管理SurfaceView的工作过程。为了让SurfaceHolder起作用,必须为SurfaceHolder添加回调方法(即第一步实现的SurfaceHolder.Callback):
    SurfaceHolder.addCallBack(SurfaceHolder.Callback);

  3. 在SurfaceView内创建第二线程的内部类(暂命名为SecondThread),它的主要任务是完成Canvas的图形绘制。为了能让SecondThread获得Canvas实例,必须给SecondThread传递在步骤二中获得的SurfaceHolder。现在就可以通过SurfaceHolder.lockCanvas()方法得到Canvas实例,并在Canvas上绘制图形。当图形绘制完成后,必须马上调用SurfaceHolder.unlockCanvasAndPost()为Canvas解锁,使其他线程可以使用该画布。

有几个注意点:

  1. 每一次通过SurfaceHolder获取的Canvas都会保持上一次绘制的状态。如果需要重新绘制图形,可以通过调用Canvas.drawColor()或Canvas.drawBitmap()来擦除上次遗留的图形。
  2. 并不一定只用第二线程来绘制图形,也可以开启第三,第四个线程来绘制图形。
  3. 注意线程安全。
  4. 不需要像View一样,调用invalidate()方法来指示图形的刷新。

SurfaceView的一个范例:
package com.sin90lzc.android.sample;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CanvasView extends SurfaceView implements SurfaceHolder.Callback {

	public static class Point {
		private float x;
		private float y;

		public Point(float x, float y) {
			this.x = x;
			this.y = y;
		}

		public float getX() {
			return x;
		}

		public void setX(float x) {
			this.x = x;
		}

		public float getY() {
			return y;
		}

		public void setY(float y) {
			this.y = y;
		}

		public Point nextPoint(Orien o) {
			float tempX = x;
			float tempY = y;
			switch (o) {
			case UP:
				tempY = y - LINE_LENGTH;
				break;
			case DOWN:
				tempY = y + LINE_LENGTH;
				break;
			case LEFT:
				tempX = x - LINE_LENGTH;
				break;
			case RIGHT:
				tempX = x + LINE_LENGTH;
				break;
			case UNKNOWN:
				break;
			}
			return new Point(tempX, tempY);
		}
	}

	enum Orien {
		UP, LEFT, DOWN, RIGHT, UNKNOWN
	}

	public static class DrawThread extends Thread {

		private List<Point> points = Collections
				.synchronizedList(new ArrayList<Point>());
		private boolean mRun;

		private Paint mPaint;
		private Orien curOrien;

		public synchronized void setRun(boolean run) {
			this.mRun = run;
			notifyAll();
		}

		public synchronized boolean getRun() {
			while (!mRun) {
				try {
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			return mRun;
		}

		//当按上下左右键时,生成相应的点坐标
		private synchronized boolean doKeyDown(int KeyCode, KeyEvent event) {
			synchronized (holder) {
				Point p = null;
				switch (KeyCode) {
				case KeyEvent.KEYCODE_DPAD_UP:
					if (curOrien != Orien.DOWN) {
						curOrien = Orien.UP;
						p = curPoint.nextPoint(curOrien);
					}
					break;
				case KeyEvent.KEYCODE_DPAD_DOWN:
					if (curOrien != Orien.UP) {
						curOrien = Orien.DOWN;
						p = curPoint.nextPoint(curOrien);
					}
					break;
				case KeyEvent.KEYCODE_DPAD_LEFT:
					if (curOrien != Orien.RIGHT) {
						curOrien = Orien.LEFT;
						p = curPoint.nextPoint(curOrien);
					}
					break;
				case KeyEvent.KEYCODE_DPAD_RIGHT:
					if (curOrien != Orien.LEFT) {
						curOrien = Orien.RIGHT;
						p = curPoint.nextPoint(curOrien);
					}
					break;
				default:
					curOrien = Orien.UNKNOWN;
				}
				if (p != null) {
					curPoint = p;
					points.add(p);
					setRun(true);
				}
				Log.i(LOG_TAG, curOrien.toString());
			}
			return true;
		}

		//当释放按键时,停止绘图
		private synchronized boolean doKeyUp(int KeyCode, KeyEvent event) {
			synchronized (holder) {
				setRun(false);
				curOrien = Orien.UNKNOWN;
			}
			return true;
		}

		SurfaceHolder holder;
		private Point curPoint;

		public DrawThread(SurfaceHolder holder) {
			this.holder = holder;
			mPaint = new Paint();
			mPaint.setColor(Color.GREEN);
			curPoint = new Point(50, 50);
			points.add(curPoint);
		}

		public void resetPoint() {
		}

		private void doDraw(Canvas canvas) {
			for (int i = 0; i + 1 < points.size(); i += 1) {
				Point lp = points.get(i);
				Point np = points.get(i + 1);
				canvas.drawLine(lp.getX(), lp.getY(), np.getX(), np.getY(),
						mPaint);
			}
		}

		@Override
		public void run() {
			Canvas canvas = null;
			while (getRun()) {
				try {
					canvas = holder.lockCanvas();
					synchronized (holder) {
						doDraw(canvas);
					}
				} finally {
					holder.unlockCanvasAndPost(canvas);
					setRun(false);
				}
			}
		}
	}

	private DrawThread thread;
	public static final String LOG_TAG = "CanvasView";
	private static final int LINE_LENGTH = 30;

	public CanvasView(Context context) {
		super(context);

	}

	public CanvasView(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		//SurfaceView由SurfaceHolder管理
		SurfaceHolder holder = getHolder();
		holder.addCallback(this);
		thread = new DrawThread(holder);
		thread.start();
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		return thread.doKeyDown(keyCode, event);
	}

	@Override
	public boolean onKeyUp(int keyCode, KeyEvent event) {
		return thread.doKeyUp(keyCode, event);
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		Log.i(LOG_TAG, "surfaceChanged");
		thread.resetPoint();
		thread.setRun(true);
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		Log.i(LOG_TAG, "surfaceCreated");
		thread.resetPoint();
		thread.setRun(true);
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		Log.i(LOG_TAG, "surfaceDestroyed");
		thread.setRun(false);
	}

}

Notice:例子中,没一次按下方向键都得把所有坐标重新绘制一遍。如果只是绘制最后一次没绘制的点时,不知道为什么会变成虚线,有待解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值