3

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.

skornos
  • 3,121
  • 1
  • 26
  • 30
  • So you just want UI elements on top of a `SurfaceView`? Something like https://www.youtube.com/watch?v=kH9kCP2T5Gg#t=28 (you can see a couple of `TextView`s overlaid on the camera preview in the top left, as well as the spinner)? – fadden Mar 09 '14 at 16:55
  • yes, that is exactly what I am looking for (to be exact I want ImageButton on the surface). But the problem is ViewGroup which lies in between SurfaceView and Activity. It turned out that it is necessary to add elements to the ViewGroup in reverse order than in *Layout (first added is the most on top) but right now the button is overlaying the whole screen and surfaceCreated() is not called. – skornos Mar 09 '14 at 17:05

2 Answers2

2

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.

Hamid Shatu
  • 9,664
  • 4
  • 30
  • 41
  • well, my app is already right now quite huge and I have created the class hierarchy as described above which provides me centered camera and all the settings. So I need to stick to it and cannot change mPreview to SurfaceView if it is Preview class now which extends ViewGroup class – skornos Mar 09 '14 at 11:24
  • or where could I add the button dynamically? – skornos Mar 09 '14 at 11:38
0

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