如何在 Xamarin.Android 中更改 Surface View 高度?

How to change Surface View Height in Xamarin.Android?

我的布局代码。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:showIn="@layout/Main">
<LinearLayout
    android:id="@+id/camera_ll"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:weightSum="100"
    android:orientation="vertical">
    <FrameLayout
        android:layout_height="0dp"
        android:layout_width="match_parent"
        android:id="@+id/frameLayout"
        android:layout_weight="90" />
    <Button
        android:layout_height="0dp"
        android:layout_width="match_parent"
        android:id="@+id/btn_capture"
        android:text="Scan Answer Sheet"
        fontPath="Fonts/Verb-Semibold.otf"
        android:textColor="@android:color/white"
        android:background="@drawable/bttn_green"
        android:layout_weight="10" />
     </LinearLayout>
  </RelativeLayout>

我的 Java 代码是这样的。

    public class CameraPreview : Activity, Android.Hardware.Camera.IPictureCallback, Android.Hardware.Camera.IPreviewCallback, Android.Hardware.Camera.IShutterCallback
{
    String PICTURE_FILENAME = "picture.jpg";
    Preview mPreview;
    Camera mCamera;
    int numberOfCameras;
    int cameraCurrentlyLocked;

    // The first rear facing camera
    int defaultCameraId;
    FrameLayout frameLayout;
    Button btn_capture;
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        // Hide the window title and go fullscreen.
        RequestWindowFeature(WindowFeatures.NoTitle);
        Window.AddFlags(WindowManagerFlags.Fullscreen);

        // Create our Preview view and set it as the content of our activity.

        SetContentView(Resource.Layout.CameraPriview);
        frameLayout = FindViewById<FrameLayout>(Resource.Id.frameLayout);
        btn_capture = FindViewById<Button>(Resource.Id.btn_capture);
        mPreview = new Preview(this, frameLayout);
        frameLayout.AddView(mPreview);
        btn_capture.Click += TakeAPicture;
        // Find the total number of cameras available
        numberOfCameras = Camera.NumberOfCameras;

        // Find the ID of the default camera
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        for (int i = 0; i < numberOfCameras; i++)
        {
            Camera.GetCameraInfo(i, cameraInfo);
            if (cameraInfo.Facing == CameraFacing.Back)
            {
                defaultCameraId = i;
            }
        }
    }
    private void TakeAPicture(object sender, EventArgs eventArgs)
    {

        Android.Hardware.Camera.Parameters p = mCamera.GetParameters();
        p.PictureFormat = Android.Graphics.ImageFormatType.Jpeg;
        mCamera.SetParameters(p);
        mCamera.TakePicture(this, this, this);

    }
    void Camera.IPictureCallback.OnPictureTaken(byte[] data, Android.Hardware.Camera camera)
    {
        FileOutputStream outStream = null;
        File dataDir = Android.OS.Environment.ExternalStorageDirectory;
        if (data != null)
        {
            try
            {
                outStream = new FileOutputStream(dataDir + "/" + PICTURE_FILENAME);
                outStream.Write(data);
                outStream.Close();
            }
            catch (FileNotFoundException e)
            {
                System.Console.Out.WriteLine(e.Message);
            }
            catch (IOException ie)
            {
                System.Console.Out.WriteLine(ie.Message);
            }
        }
    }

    void Camera.IPreviewCallback.OnPreviewFrame(byte[] b, Android.Hardware.Camera c)
    {

    }

    void Camera.IShutterCallback.OnShutter()
    {

    }
    protected override void OnResume()
    {
        base.OnResume();

        // Open the default i.e. the first rear facing camera.
        mCamera = Camera.Open();
        cameraCurrentlyLocked = defaultCameraId;
        mPreview.PreviewCamera = mCamera;
        mCamera.SetDisplayOrientation(90);



    }


    protected override void OnPause()
    {
        base.OnPause();

        // Because the Camera object is a shared resource, it's very
        // important to release it when the activity is paused.
        if (mCamera != null)
        {
            mPreview.PreviewCamera = null;
            mCamera.Release();
            mCamera = null;
        }
    }

    public override bool OnCreateOptionsMenu(IMenu menu)
    {
        // Inflate our menu which can gather user input for switching camera
        //MenuInflater.Inflate(Resource.Menu.camera_menu, menu);
        return true;
    }


}

表面视图代码。

  class Preview : ViewGroup, ISurfaceHolderCallback
{
    string TAG = "Preview";
    FrameLayout f;
    SurfaceView mSurfaceView;
    ISurfaceHolder mHolder;
    Camera.Size mPreviewSize;
    IList<Camera.Size> mSupportedPreviewSizes;
    Camera _camera;

    public Camera PreviewCamera
    {
        get { return _camera; }
        set
        {
            _camera = value;
            if (_camera != null)
            {
                mSupportedPreviewSizes = PreviewCamera.GetParameters().SupportedPreviewSizes;
                RequestLayout();
            }
        }
    }

    public Preview(Context context, FrameLayout f) : base(context)
    {
        this.f = f;
        mSurfaceView = new SurfaceView(context);
        AddView(mSurfaceView);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = mSurfaceView.Holder;
        mHolder.AddCallback(this);
        mHolder.SetType(SurfaceType.PushBuffers);

    }

    public void SwitchCamera(Camera camera)
    {
        PreviewCamera = camera;

        try
        {
            camera.SetPreviewDisplay(mHolder);
        }
        catch (Java.IO.IOException exception)
        {
            Log.Error(TAG, "IOException caused by setPreviewDisplay()", exception);
        }

        Camera.Parameters parameters = camera.GetParameters();
        parameters.SetPreviewSize(mPreviewSize.Width, mPreviewSize.Height);

        RequestLayout();

        camera.SetParameters(parameters);
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // We purposely disregard child measurements because act as a
        // wrapper to a SurfaceView that centers the camera preview instead
        // of stretching it.
        int width = ResolveSize(SuggestedMinimumWidth, widthMeasureSpec);
        int height = ResolveSize(SuggestedMinimumHeight, heightMeasureSpec);
        SetMeasuredDimension(width, height);

        if (mSupportedPreviewSizes != null)
        {
           mPreviewSize = GetOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }
    }

    protected override void OnLayout(bool changed, int l, int t, int r, int b)
    {
        if (changed && ChildCount > 0)
        {
            View child = GetChildAt(0);

            int width = r - l;
            int height = b - t;

            int previewWidth = width;
            int previewHeight = height;
            if (mPreviewSize != null)
            {
                previewWidth = mPreviewSize.Width;
                previewHeight = mPreviewSize.Height;
            }

            // Center the child SurfaceView within the parent.
            if (width * previewHeight > height * previewWidth)
            {
                int scaledChildWidth = previewWidth * height / previewHeight;
                child.Layout((width - scaledChildWidth) / 2, 0,
                             (width + scaledChildWidth) / 2, height);
            }
            else
            {
                int scaledChildHeight = previewHeight * width / previewWidth;
                child.Layout(0, (height - scaledChildHeight) / 2,
                             width, (height + scaledChildHeight) / 2);
            }
        }
    }

    public void SurfaceCreated(ISurfaceHolder holder)
    {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try
        {
            if (PreviewCamera != null)
            {

                PreviewCamera.SetPreviewDisplay(holder);

            }
        }
        catch (Java.IO.IOException exception)
        {
            Log.Error(TAG, "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void SurfaceDestroyed(ISurfaceHolder holder)
    {
        // Surface will be destroyed when we return, so stop the preview.
        if (PreviewCamera != null)
        {
            PreviewCamera.StopPreview();
        }
    }

    private Camera.Size GetOptimalPreviewSize(IList<Camera.Size> sizes, int w, int h)
    {
        const double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double)w / h;

        if (sizes == null)
            return null;

        Camera.Size optimalSize = null;
        double minDiff = Double.MaxValue;

        int targetHeight = h;

        // Try to find an size match aspect ratio and size
        foreach (Camera.Size size in sizes)
        {
            double ratio = (double)size.Width / size.Height;

            if (Math.Abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                continue;

            if (Math.Abs(size.Height - targetHeight) < minDiff)
            {
                optimalSize = size;
                minDiff = Math.Abs(size.Height - targetHeight);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null)
        {
            minDiff = Double.MaxValue;
            foreach (Camera.Size size in sizes)
            {
                if (Math.Abs(size.Height - targetHeight) < minDiff)
                {
                    optimalSize = size;
                    minDiff = Math.Abs(size.Height - targetHeight);
                }
            }
        }


        return optimalSize;
    }

    public void SurfaceChanged(ISurfaceHolder holder, Android.Graphics.Format format, int w, int h)
    {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        Camera.Parameters parameters = PreviewCamera.GetParameters();
        parameters.SetPreviewSize(mPreviewSize.Width, mPreviewSize.Height);
        RequestLayout();

        PreviewCamera.SetParameters(parameters);
        PreviewCamera.StartPreview();
    }


}

输出:

现在我想增加相机高度以填充所有可用的space,但对我没有任何作用。如果有人知道解决方案请帮助谢谢。

Now i want to increase the camera height to fill all available space but nothing working for me. If anyone know the solution please help thanks.

预览尺寸的设置代码在PreviewOnLayout方法中:

protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
    if (changed && ChildCount > 0)
    {
        View child = GetChildAt(0);

        int width = r - l;
        int height = b - t;

        int previewWidth = width;
        int previewHeight = height;
        if (mPreviewSize != null)
        {
            previewWidth = mPreviewSize.Width;
            previewHeight = mPreviewSize.Height;
        }

        // Center the child SurfaceView within the parent.
        if (width * previewHeight > height * previewWidth)
        {
            int scaledChildWidth = previewWidth * height / previewHeight;
            child.Layout((width - scaledChildWidth) / 2, 0,
                         (width + scaledChildWidth) / 2, height);
        }
        else
        {
            int scaledChildHeight = previewHeight * width / previewWidth;
            child.Layout(0, (height - scaledChildHeight) / 2,
                         width, (height + scaledChildHeight) / 2);
        }
    }
}

这里我不明白代码的意思。但是通过 child.Layout(0, (height - scaledChildHeight) / 2,width, (height + scaledChildHeight) / 2);,您正在将预览 window 的顶部边界和底部边界减小到 (height - scaledChildHeight) / 2(height + scaledChildHeight) / 2)

因此,要增加相机高度以填充所有可用的 space,您需要修改此代码段。 例如:

int LeftBoundary=0,TopBoundary=0;
int RightBoundary=r,BottomBoundary=b;
child.Layout(LeftBoundary,TopBoundary,RightBoundary,BottomBoundary));