Android button on top of Camera preview

I would like to add button on Android CameraPreview. Basically the hierarchy is following:

  • Activity
    • ViewGroup
      • SurfaceView

ViewGroup is wrapper around SurfaceView and centers CameraPreview.

My current code in Activity.java is working (without the button):

mPreview = new Preview(this, mCamera, mJavaDetector);
setContentView(mPreview);

Now I have created layout and want to place there a button. My layout main.xml looks like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="horizontal"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:id="@+id/layout">

    <LinearLayout
        android:id="@+id/preview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal"
        android:visibility="visible"
        android:layout_alignParentTop="true">
    </LinearLayout>

    <Button android:text="Freeze" android:id="@+id/someButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </Button>      

</RelativeLayout>

I have changed Activity.java:

setContentView(R.layout.main); 
mPreview = new Preview(this, mCamera, mJavaDetector);

LinearLayout ll = (LinearLayout)findViewById(R.id.preview);
if(ll != null)
{
    ll.addView(mPreview);
}

And in Preview.java is created SurfaceView

mCameraPreview = new CameraPreview(context, camera, mJavaDetector);
addView(mCameraPreview);

Now there is only the button on the screen but no CameraPreview. Could you tell me what am I doing wrong? Thanks.

EDIT:

So let's say I have main.xml like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content">


    <fit.vutbr.faceswap.Preview
        android:id="@+id/preview"  
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content">

        <fit.vutbr.faceswap.CameraPreview
            android:id="@+id/camerapreview"  
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content">
        </fit.vutbr.faceswap.CameraPreview>

    </fit.vutbr.faceswap.Preview>


    <ImageButton
        android:id="@+id/imageButton1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@null"
        android:src="@drawable/switch_100px_white" />     

</LinearLayout>

Inside Activity.java:

setContentView(R.layout.main);
mPreview = (Preview) findViewById(R.id.preview);
mPreview.setPreview(this, mCamera, mJavaDetector);

Inside Preview.java:

mCameraPreview = (CameraPreview) findViewById(R.id.camerapreview);
mCameraPreview.setCameraPreview(context, camera, mJavaDetector);

Where is the mistake in here?

EDIT2:

Ok, it turned out that if I use main.xml like this I can see surfaceView:

<?xml version="1.0" encoding="utf-8"?>
<fit.vutbr.faceswap.Preview
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/preview"  
    android:layout_width="match_parent" 
    android:layout_height="match_parent"
    android:orientation="horizontal" >

   <!--  <ImageButton
            android:id="@+id/switch_camera_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@null"
            android:src="@drawable/switch_100px_white" />    
    -->        
    <fit.vutbr.faceswap.CameraPreview
        android:id="@+id/camerapreview"  
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content">
    </fit.vutbr.faceswap.CameraPreview>


</fit.vutbr.faceswap.Preview>

Also I have found out that ViewGroup uses reverse order when adding new Views than other Layouts so the first added is the most on top.

Right now if I uncomment ImageButton I get button over the whole screen and surfaceCreated() method from SurfaceView is never called.

Answers


Use SurfaceView instead of LinearLayout for your camera preview as below...

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content">

    <SurfaceView
        android:id="@+id/cpPreview"
        android:layout_width="fill_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:layout_gravity="center" />

   <Button android:text="Freeze" 
        android:id="@+id/someButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

Then initialize the preview as below...

  private SurfaceView preview=null;
  private SurfaceHolder previewHolder=null;
  private Camera camera=null;

  @Override
  public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);

     setContentView(R.layout.main);

     preview = (SurfaceView)findViewById(R.id.preview);
     previewHolder = preview.getHolder();
     previewHolder.addCallback(surfaceCallback);
     previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  }

  @Override
  public void onResume() {
    super.onResume();

    camera=Camera.open();
    startPreview();
  }

This project may help you more.


I've done it using RelativeLayout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">

<FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_alignParentBottom="true"
    android:text="Record baby!"/>

In Activity camera preview (SurfaceView) is being put to FrameLayout:

CameraPreview cameraPreview = new CameraPreview(this);
cameraPreviewFrame.addView(cameraPreview);

Worked like a charm for me in my app


Need Your Help

Move Camera Over Terrain Using Touch Input in Unity 3D

c# ios 3d touch unity3d

I am new to Unity and I am trying to figure out how to move the camera over a map/terrain using touch input. The camera would be looking down at the terrain with a rotation of (90,0,0). The terrain...

How to View Number of OpenGL Draw Calls In XCode

xcode opengl-es

In XCode, I can click "Analyze" in the Debug Navigator to capture an OpenGL frame. It will show me the total number of OpenGL calls. However, I am interested in only the number of draw calls. Is...