如何在 Android 上的相机使用的 SurfaceView 上绘制叠加层?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2933882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:57:32  来源:igfitidea点击:

How to draw an overlay on a SurfaceView used by Camera on Android?

androidcamerasurfaceview

提问by Cristian

I have a simple program that draws the preview of the Camerainto a SurfaceView. What I'm trying to do is using the onPreviewFramemethod, which is invoked each time a new frame is drawn into the SurfaceView, in order to execute the invalidatemethod which is supposed to invoke the onDrawmethod. In fact, the onDrawmethod is being invoked, but nothing there is being printed (I guess the camera preview is overwriting the text I'm trying to draw).

我有一个简单的程序,可以将预览绘制CameraSurfaceView. 我想要做的是使用该onPreviewFrame方法,每次将新帧绘制到 中时都会调用该方法,SurfaceView以便执行invalidate应该调用该onDraw方法的方法。事实上,onDraw正在调用该方法,但没有打印任何内容(我猜相机预览覆盖了我试图绘制的文本)。

This is a simplify version of the SurfaceViewsubclass I have:

这是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);
 }
}

回答by CommonsWare

SurfaceViewprobably does not work like a regular Viewin this regard.

SurfaceViewView在这方面可能不像常规那样工作。

Instead, do the following:

相反,请执行以下操作:

  1. Put your SurfaceViewinside of a FrameLayoutor RelativeLayoutin your layout XML file, since both of those allow stacking of widgets on the Z-axis
  2. Move your drawing logic into a separate custom Viewclass
  3. Add an instance of the custom View class to the layout XML file as a child of the FrameLayoutor RelativeLayout, but have it appear after the SurfaceView
  1. 将您的SurfaceView内部 a FrameLayoutRelativeLayout放在您的布局 XML 文件中,因为这两个文件都允许在 Z 轴上堆叠小部件
  2. 将您的绘图逻辑移动到一个单独的自定义View类中
  3. 将自定义 View 类的实例作为FrameLayoutor 的子项添加到布局 XML 文件中RelativeLayout,但让它出现在SurfaceView

This will cause your custom Viewclass to appear to float above the SurfaceView.

这将导致您的自定义View类看起来漂浮在SurfaceView.

See here for a sample projectthat layers popup panels above a SurfaceViewused for video playback.

请参阅此处的示例项目,该项目将弹出面板分层SurfaceView用于视频播放。

回答by maximus

Try calling setWillNotDraw(false)from surfaceCreated:

尝试调用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");
}

and calling invalidatefrom onTouchEvent:

invalidateonTouchEvent

public boolean onTouch(View v, MotionEvent event) {

    invalidate();
    return true;
}

回答by Devashish Kunal

I think you should call the super.draw()method first before you do anything in surfaceView's draw method.

我认为您应该先调用该super.draw()方法,然后再在 SurfaceView 的 draw 方法中执行任何操作。