如何实现Android SurfaceView

 我来答
可以叫我表哥
推荐于2016-05-20 · 知道合伙人数码行家
可以叫我表哥
知道合伙人数码行家
采纳数:25897 获赞数:1464978
2010年毕业于北京化工大学北方学院计算机科学与技术专业毕业,学士学位,工程电子技术行业4年从业经验。

向TA提问 私信TA
展开全部
  SurfaceView是View的继承结构中一个比较特殊的子类,它的作用是提供一个第二线程来完成图形的绘制。因此应用程序不需要等待View的图形绘制,第二线程会异步完成图形的绘制。
  SurfaceView实现的步骤:

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

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

  有几个注意点:

  每一次通过SurfaceHolder获取的Canvas都会保持上一次绘制的状态。如果需要重新绘制图形,可以通过调用Canvas.drawColor()或Canvas.drawBitmap()来擦除上次遗留的图形。
  并不一定只用第二线程来绘制图形,也可以开启第三,第四个线程来绘制图形。
  注意线程安全。
  不需要像View一样,调用invalidate()方法来指示图形的刷新。
  SurfaceView的一个范例:
  [java] view plaincopyprint?
  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:例子中,没一次按下方向键都得把所有坐标重新绘制一遍。如果只是绘制最后一次没绘制的点时,不知道为什么会变成虚线,有待解决。
本回答被提问者和网友采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式