web-dev-qa-db-ja.com

Androidのカメラで使用されるSurfaceViewにオーバーレイを描画する方法は?

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);
 }
}
68
Cristian

SurfaceViewは、おそらくこの点で通常のViewのようには機能しません。

代わりに、次を実行します。

  1. SurfaceViewをレイアウトXMLファイルのFrameLayoutまたはRelativeLayoutの内側に配置します。どちらもZ軸にウィジェットをスタックできるためです。
  2. 描画ロジックを個別のカスタムViewクラスに移動します
  3. カスタムViewクラスのインスタンスをFrameLayoutまたはRelativeLayoutの子としてレイアウトXMLファイルに追加しますが、SurfaceViewの後に表示します

これにより、カスタムViewクラスがSurfaceViewの上に浮いているように見えます。

サンプルプロジェクトについてはこちらをご覧ください ビデオ再生に使用されるSurfaceViewの上にポップアップパネルを重ねます。

84
CommonsWare

surfaceCreatedからsetWillNotDraw(false)を呼び出してみてください:

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;
}
17
maximus

SurfaceViewのdrawメソッドで何かを行う前に、最初にsuper.draw()メソッドを呼び出す必要があると思います。

1
Devashish Kunal