Как нарисовать наложение на SurfaceView, используемое камерой на Android?

У меня есть простая программа, которая рисует предварительный просмотр Camera в SurfaceView. То, что я пытаюсь сделать, это использовать метод onPreviewFrame, который вызывается каждый раз, когда новый кадр втягивается в SurfaceView, чтобы выполнить метод invalidate, который должен вызывать метод onDraw, Фактически, метод onDraw вызывается, но ничего не печатается (я думаю, предварительный просмотр камеры переписывает текст, который я пытаюсь нарисовать).

Это упрощенная версия подкласса SurfaceView:

public class Superficie extends SurfaceView implements SurfaceHolder.Callback {
 SurfaceHolder mHolder;
 public Camera camera;
 Superficie(Context context) {
  super(context);
  mHolder = getHolder();
  mHolder.addCallback(this);
  mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
 }
 public void surfaceCreated(final SurfaceHolder holder) {
  camera = Camera.open();
  try {
   camera.setPreviewDisplay(holder);
   camera.setPreviewCallback(new PreviewCallback() {
    public void onPreviewFrame(byte[] data, Camera arg1) {
     invalidar();
    }
   });
  } catch (IOException e) {}
 }
 public void invalidar(){
  invalidate();
 }
 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
  Camera.Parameters parameters = camera.getParameters();
  parameters.setPreviewSize(w, h);
  camera.setParameters(parameters);
  camera.startPreview();
 }
 @Override
 public void draw(Canvas canvas) {
  super.draw(canvas);
  // nothing gets drawn :(
  Paint p = new Paint(Color.RED);
  canvas.drawText("PREVIEW", canvas.getWidth() / 2,
    canvas.getHeight() / 2, p);
 }
}

Ответ 1

SurfaceView, вероятно, не работает как обычный View в этом отношении.

Вместо этого выполните следующие действия:

  • Поместите свой SurfaceView внутри FrameLayout или RelativeLayout в ваш XML файл макета, поскольку оба они позволяют укладывать виджеты на ось Z
  • Переместите логику рисования в отдельный пользовательский класс View
  • Добавить экземпляр пользовательского вида класс в XML файл макета как дочерний элемент FrameLayout или RelativeLayout, но если он появится после SurfaceView

Это приведет к тому, что ваш пользовательский класс View будет плавать над SurfaceView.

См. здесь пример проекта, который отображает всплывающие панели выше SurfaceView, используемые для воспроизведения видео.

Ответ 2

Попробуйте вызвать setWillNotDraw(false) из surfaceCreated:

public void surfaceCreated(SurfaceHolder holder) {
    try {
        setWillNotDraw(false); 
        mycam.setPreviewDisplay(holder);
        mycam.startPreview();
    } catch (Exception e) {
        e.printStackTrace();
        Log.d(TAG,"Surface not created");
    }
}

@Override
protected void onDraw(Canvas canvas) {

    canvas.drawRect(area, rectanglePaint);
    Log.w(this.getClass().getName(), "On Draw Called");
}

и вызывая invalidate от onTouchEvent:

public boolean onTouch(View v, MotionEvent event) {

    invalidate();
    return true;
}

Ответ 3

Я думаю, вы должны сначала вызвать метод super.draw(), прежде чем делать что-либо в методе рисования surfaceView.