如何在 XML 布局中使用扩展类?

Posted

技术标签:

【中文标题】如何在 XML 布局中使用扩展类?【英文标题】:How do you use an extended class in XML layout? 【发布时间】:2015-10-30 04:58:45 【问题描述】:

我为相机预览创建了 SurfaceView 的扩展类。

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());
        
    

在这样的活动中使用时,它可以作为全屏预览:

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);
    

当我尝试在 XML 布局文件中使用它时,它会给出 ClassNotFoundException。

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

我需要做什么才能让它工作? 如何在 SurfaceView 中放置相机预览?

【问题讨论】:

【参考方案1】:

假设包含新视图的包被称为:com.ranandar.views

在您的 xml 中执行以下操作:

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

这会在 com.ranandar.views 包中查找,找到定义该视图的类并使用它。

您的活动中存在问题。您将内容视图设置为表面视图,这是不对的。

编辑:添加您请求的示例。

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
    ...

所以我所做的是添加了定义自定义视图所需的构造函数,并在 XML 中使用它。您需要定义额外的构造函数,以便在 XML 中使用它时,将属性集传递给视图。属性集是您声明的各种字段,如 layout_width/height、背景等。否则,如果没有此构造函数,CameraPreview 将无法膨胀,因为传递了属性集而没有构造函数来处理它。双参数构造函数 super(context, attrs) 中的调用使用您定义的属性进行处理。

您可能需要进一步学习的文档:Creating Custom Views

需要为您的 XML 文件创建一个 ViewGroup 类的根视图,如 RelativeLayout、LinearLayout 等...在这种情况下进行框架布局:

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

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

</FrameLayout>

假设这个 xml 文件被称为 activity_main.xml

执行以下操作:

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);
    

始终确保首先设置内容视图,然后再进行可能调用布局的任何其他操作。这可能对您来说是个问题

【讨论】:

另外,您需要在 CameraPreview 上实现两参数构造函数,即采用 ContextAttributeSet 的构造函数。 抱歉 Lucas,但这样做会导致 InflateException。上面显示的活动只是一个测试。 你按照常识说的做了吗?? 另外,我只是在回答关于如何使用自定义视图的问题:P 我想我不明白如何“实现双参数构造函数”。现在我得到 InflateException 和 NoSuchMethodException。甚至可以向 Java 中的可视化组件添加功能吗?我在 C# 中使用继承毫无问题地做到了这一点。关于如何做到这一点的示例或一些文档将非常有帮助。

以上是关于如何在 XML 布局中使用扩展类?的主要内容,如果未能解决你的问题,请参考以下文章

在哪里以及如何找到 Android 类使用的布局文件?

如何在一个Activity里使用另一个xml布局文件

Android在Activity里如何获得另一个xml布局文件的控件

在Android中,如何将数据从类传递到相应的布局/片段文件?

如何在通知内容扩展中使用多行 UILabel / 自动布局调试布局

在布局 xml 文件中使用包含时如何指定 id