user3530196
user3530196

Reputation:

How do you use an extended class in XML layout?

I have created an extended class of SurfaceView for a camera preview.

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    SurfaceHolder mHolder;
    Camera mCamera;

    CameraPreview(Context context) {
        super(context);

        mHolder = this.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try {
            mCamera = Camera.open();
            mCamera.setPreviewDisplay(holder);
        } catch (Exception e){
            Log.wtf("surfaceCreated", e.toString());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        try {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        } catch (Exception e){
            Log.wtf("surfaceDestroyed", e.toString());
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        try {
            Camera.Parameters parameters = mCamera.getParameters();
            // parameters.setPreviewSize(w, h);
            // parameters.setPreviewSize(222, 222);
            mCamera.setParameters(parameters);
            mCamera.startPreview();
        } catch (Exception e){
            Log.wtf("surfaceChanged", e.toString());
        }
    }
}

It is working as a full screen preview when used in an activity like this:

public class CameraActivity extends Activity {
    CameraPreview mPreview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE); 
        mPreview = new CameraPreview(this);
        setContentView(mPreview);
    }
}

When I try to use it in an XML layout file it gives a ClassNotFoundException.

<CameraPreview class="com.xxxxxx.camera3.CameraPreview"
    android:layout_width="260dp"
    android:layout_height="260dp"
    android:id="@+id/surfaceView"
    android:background="#ff404040"
    android:layout_gravity="center_horizontal"/> 

What do I need to do to make it work? How can I put a camera preview in a SurfaceView?

Upvotes: 2

Views: 1460

Answers (1)

Lucas Crawford
Lucas Crawford

Reputation: 3118

Say your package that contains the new View is called: com.ranandar.views

In your xml do the following:

<com.ranandar.views.CameraPreview
    android:layout_width="260dp"
    android:layout_height="260dp"
    android:id="@+id/surfaceView"
    android:background="#ff404040"
    android:layout_gravity="center_horizontal"/> 

This looks in the package com.ranandar.views, finds the class that defines that view, and uses it.

There is an issue though in your activity. You are setting the content view to just be that surface view, that isn't right.

EDIT: Adding the example you requested.

public class CameraPreview extends SurfaceView implements   SurfaceHolder.Callback {
    SurfaceHolder mHolder;
    Camera mCamera;

    CameraPreview(Context context) {
        super(context);
        init();
    }

    CameraPreview(Context context, AttributeSet attrs){
        super(context, attrs);
        init();
    }

    public void init(){
        mHolder = this.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    //additionally with all your other code
    ...
}

So what I have done is added the constructor needed for defining a custom view, and using it within XML. You need to define the additional constructor, so that when you are using it in XML, the attribute set is passed to the view. The attribute set is the various fields you declared like layout_width/height, background etc. Otherwise, without this constructor, the CameraPreview is unable to be inflated due to being passed the attribute set with no constructor to handle it. The call in the two-parameter constructor super(context, attrs) handles using the attributes you defined.

Documentation you might need for further learning: Creating Custom Views

Need to make the root view for your XML file a ViewGroup class, like RelativeLayout, LinearLayout, etc... In this case do a frame layout:

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

    <com.ranandar.views.CameraPreview
        android:id="@+id/camera_preview"
        android:layout_width="260dp"
        android:layout_height="260dp"
        android:id="@+id/surfaceView"
        android:background="#ff404040"
        android:layout_gravity="center_horizontal"/> 

</FrameLayout>

Say this xml file was called activity_main.xml

do the following:

public class CameraActivity extends Activity {
    CameraPreview mPreview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        requestWindowFeature(Window.FEATURE_NO_TITLE); 
        mPreview = (CameraPreview) findViewById(R.id.camera_preview);
    }
}

Always make sure to setContentView first, before anything else that might call a component to your layout. This might've been an issue for you

Upvotes: 5

Related Questions