Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Layered SurfaceViews in a FrameLayout in Android

I am attempting to build an augmented reality application for Android and have come across the problem of layering surface views. I need a surface view to display the camera preview onto which I will overlay graphics, and I need a surface view to draw my graphics on. This second surface also needs to be drawn above the camera preview but have a transparent background. In my current implementation, I have both surface views working and appearing as they are supposed to, but the background is not transparent and therefore there is no appearance of the second surface view with the graphics drawn being superimposed on the camera preview surface view. How could this be achieved? Upon searching numerous stack overflow questions as well as other forums I've come across many conflicting opinions pertaining to this matter. Some say that layering surface views in Android is impossible whilst others say that it is a matter of using a different layout (FrameLayout vs. LinearLayout?) Specifically, my implementation includes two views: a class, CustomCameraView, that extends SurfaceView, and a class, CustomDrawView, that also extends SurfaceView contained in a FrameLayout with the CustomDrawView appearing after the CustomCameraView. How can these be layered so that CustomDrawView seems superimposed on CustomCameraView?

like image 358
Zain Avatar asked Feb 11 '11 04:02

Zain


2 Answers

I think a lot of people have tried this. A Google Enginee stated (here) clearly, that you should avoid stacking Surface Views. Even if somebody has found some trick to do it, it is probably incompatible and will lead to problems.

I think this gives three options, depending on your requirements:

  • View(s) on Top of Surface View

Use a Surface View for the Camera preview and stack Views on top of it. The disadvantage of this approach is that drawing on "normal" Views a) is slower and b) takes place in the UI thread. You can get around b) if you implement the threads yourself. But generally, that is probably the way to go if your overlays contain something like UI elements or a few Drawables that don't need to be updated too often.

  • Do everything in a SurfaceView

This will give yo better performance and less overhead during runtime. You have just one SurfaceView. Composite the overlays on your SurfaceView and and draw everything there. Of course, you can combine both approaches.

  • Do everything in a GLSurfaceView

This is probably the way to go for real performance. Like above, but with the camera view rendering to a OpenGL texture in a GLSurfaceView.

like image 103
rgr_mt Avatar answered Nov 11 '22 17:11

rgr_mt


I got this working having 2 transparent views above the camera's SurfaceView using the following approach:

My activity sets up all its views in the onCreate() method, I make no use of any layout file for that. It looks as follows:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(null); //savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

    cameraPreview = new CameraPreview(this);
    addContentView(cameraPreview, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

    animationView = new AnimationView(this);
    addContentView(animationView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

    crosslinesView = new CrosslinesView(this);
    addContentView(crosslinesView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
}

cameraPreview is of type SurfaceView, animationView and crosslinesViews are of type View. The onDraw() of the 2 latter views looks as follows:

protected void onDraw(Canvas canvas) {
    // Have the view being transparent
    canvas.drawARGB(0, 0, 0, 0);
    // Your drawing code goes here
    // ...
}

Good luck!

like image 2
Lars Blumberg Avatar answered Nov 11 '22 19:11

Lars Blumberg