Cómo dibujar una superposición en un SurfaceView utilizado por la cámara en Android?


Tengo un programa simple que dibuja la vista previa del Camera en un SurfaceView. Lo que estoy tratando de hacer es usar el método onPreviewFrame, que se invoca cada vez que se dibuja un nuevo marco en el SurfaceView, para ejecutar el método invalidate que se supone que invoca el método onDraw. De hecho, se está invocando el método onDraw, pero no se está imprimiendo nada (supongo que la vista previa de la cámara está sobrescribiendo el texto que estoy tratando de dibujar).

Esta es una versión simplificada de la subclase SurfaceView I tienen:

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);
 }
}
Author: Cristian, 2010-05-29

3 answers

SurfaceView probablemente no funciona como un regular View en este sentido.

En su lugar, haga lo siguiente:

  1. Ponga su SurfaceView dentro de una FrameLayout o RelativeLayout en su archivo XML de diseño, ya que ambos aquellos permiten apilar widgets en el eje Z
  2. Mueve tu lógica de dibujo en una clase personalizada View
  3. Agregar una instancia de la vista personalizada clase al archivo XML de diseño como hijo del FrameLayout o RelativeLayout, pero que aparezca después de la SurfaceView

Esto hará que su clase personalizada View aparezca flotando por encima de SurfaceView.

Vea aquí un proyecto de ejemplo que capas de paneles emergentes por encima de un SurfaceView utilizado para la reproducción de vídeo.

 83
Author: CommonsWare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-02 05:15:27

Intenta llamar a setWillNotDraw(false) desde 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");
}

Y llamando invalidate desde onTouchEvent:

public boolean onTouch(View v, MotionEvent event) {

    invalidate();
    return true;
}
 17
Author: maximus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-16 23:19:18

Creo que deberías llamar al método super.draw() primero antes de hacer algo en el método draw de SurfaceView.

 1
Author: Devashish Kunal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-20 09:12:01