Android 카메라 미리보기 확장 null){

Android에서 사용자 정의 카메라 작업을 수행하려고 노력했지만 카메라를 회전하면 표면보기의 가로 세로 비율이 엉망이됩니다.

활동에 대한 oncreate에서 카메라의 매개 변수를 표시하는 표면보기를 유지하는 프레임 레이아웃을 설정했습니다.

//FrameLayout that will hold the camera preview
        FrameLayout previewHolder = (FrameLayout) findViewById(R.id.camerapreview);

        //Setting camera's preview size to the best preview size
        Size optimalSize = null;
        camera = getCameraInstance();
        double aspectRatio = 0;
        if(camera != null){
            //Setting the camera's aspect ratio
            Camera.Parameters parameters = camera.getParameters();
            List<Size> sizes = parameters.getSupportedPreviewSizes();
            optimalSize = CameraPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
            aspectRatio = (float)optimalSize.width/optimalSize.height;
        }

        if(optimalSize!= null){
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
            previewHolder.setLayoutParams(params);
            LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
            cameraPreview.setLayoutParams(surfaceParams);

        }

        cameraPreview.setCamera(camera);

        //Adding the preview to the holder
        previewHolder.addView(cameraPreview);

그런 다음 Surface 뷰에서 카메라의 매개 변수가 표시되도록 설정했습니다.

public void setCamera(Camera camera) {
        if (mCamera == camera) { return; }

        mCamera = camera;

        if (mCamera != null) {
            requestLayout();

            try {
                mCamera.setPreviewDisplay(mHolder);
            } catch (IOException e) {
                e.printStackTrace();
            }


            if(mCamera != null){
                //Setting the camera's aspect ratio
                Camera.Parameters parameters = mCamera.getParameters();
                List<Size> sizes = parameters.getSupportedPreviewSizes();
                Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);

                parameters.setPreviewSize(optimalSize.width, optimalSize.height);
                mCamera.setParameters(parameters);
            }

            /*
              Important: Call startPreview() to start updating the preview surface. Preview must
              be started before you can take a picture.
              */
            mCamera.startPreview();
        }

    }

여기에 이미지 설명을 입력하십시오

휴대 전화를 돌리면 LEGO 남자가 키가 커지고 날씬해 짐을 알 수 있습니다.

카메라 뷰의 종횡비가 올바른지 어떻게 확인할 수 있습니까?



답변

API 데모를 기반으로이 방법을 사용하여 미리보기 크기를 얻습니다.

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio=(double)h / w;

        if (sizes == null) return null;

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

        int targetHeight = h;

        for (Camera.Size size : 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);
            }
        }

        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }

보시다시피 화면의 너비와 높이를 입력해야합니다. 이 방법은 해당 값을 기준으로 화면 비율을 계산 한 다음 supportedPreviewSizes 목록에서 사용 가능한 값 중에서 가장 적합한 것을 선택합니다. 다음을 사용하여 Camera 객체가 null이 아닌 곳에 supportedPreviewSize 목록을 가져옵니다.

mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();

그런 다음 onMeasure에서 다음과 같이 최적의 미리보기 크기를 얻을 수 있습니다.

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        setMeasuredDimension(width, height);

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

그런 다음 SurfaceChanged 메서드의 코드에서 CameraActivity 코드의 API 데모 구조를 사용한다고 말한 것처럼 Eclipse에서 생성 할 수 있습니다.

Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();

그리고 당신과 같은 응용 프로그램을 거의했기 때문에 힌트가 하나 있습니다. 카메라 활동에 대한 모범 사례는 StatusBar를 숨기는 것입니다. Instagram과 같은 응용 프로그램이하고 있습니다. 화면 높이 값이 줄어들고 비율 값이 변경됩니다. 일부 장치에서 이상한 미리보기 크기를 얻을 수 있습니다 (SurfaceView가 약간 잘림).


질문에 대답하기 위해 미리보기 비율이 올바른지 확인하는 방법은 무엇입니까? 그런 다음 설정 한 매개 변수의 높이와 너비를 가져옵니다.

mCamera.setParameters(parameters);

설정 비율은 높이 / 너비와 같습니다. 카메라를 화면에서보기 좋게하려면 카메라로 설정 한 매개 변수의 높이 / 너비 비율이 화면의 높이 (빼기 상태 표시 줄) / 너비 비율과 같아야합니다.


답변

F1Sher의 솔루션은 훌륭하지만 때때로 작동하지 않습니다. 특히, SurfaceView가 전체 화면을 덮지 않는 경우. 이 경우 onMeasure () 메서드를 재정의해야합니다. 참조를 위해 여기에 코드를 복사했습니다.

너비를 기준으로 surfaceView를 측정 했으므로 화면 끝에 약간의 흰색 간격이있어 디자인으로 채 웠습니다. 높이를 유지하고 너비를 비율에 곱하여 높이면이 문제를 해결할 수 있습니다. 그러나 surfaceView가 약간 손상됩니다.

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "CameraPreview";

    private Context mContext;
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private List<Camera.Size> mSupportedPreviewSizes;
    private Camera.Size mPreviewSize;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mContext = context;
        mCamera = camera;

        // supported preview sizes
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        for(Camera.Size str: mSupportedPreviewSizes)
                Log.e(TAG, str.width + "/" + str.height);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // empty. surfaceChanged will take care of stuff
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + h);
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (mHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or reformatting changes here
        // start preview with new settings
        try {
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
            mCamera.setParameters(parameters);
            mCamera.setDisplayOrientation(90);
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

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

        if (mPreviewSize!=null) {
            float ratio;
            if(mPreviewSize.height >= mPreviewSize.width)
                ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
            else
                ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;

            // One of these methods should be used, second method squishes preview slightly
            setMeasuredDimension(width, (int) (width * ratio));
  //        setMeasuredDimension((int) (width * ratio), height);
        }
    }

    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) h / w;

        if (sizes == null)
            return null;

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

        int targetHeight = h;

        for (Camera.Size size : sizes) {
            double ratio = (double) size.height / size.width;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                continue;

            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }

        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }

        return optimalSize;
    }
}


답변

참고 : 내 솔루션은 HESAM 솔루션의 연속입니다. https://stackoverflow.com/a/22758359/1718734

내가 다루는 내용 : Hesam은 다음과 같이 일부 전화기에 약간의 공백이 나타날 수 있다고 말했습니다.

참고 : 화면비는 정확하지만 카메라가 전체 화면을 채우지는 않습니다.

Hesam은 두 번째 해결책을 제안했지만 미리보기를 무너 뜨 렸습니다. 그리고 일부 장치에서는 심하게 왜곡됩니다.

이 문제를 어떻게 해결합니까? 화면이 가득 찰 때까지 종횡비를 곱하면 간단합니다. Snapchat, WhatsApp 등과 같은 인기있는 여러 앱이 동일한 방식으로 작동한다는 것을 알았습니다.

onMeasure 메소드에 이것을 추가하기 만하면됩니다.

float camHeight = (int) (width * ratio);
    float newCamHeight;
    float newHeightRatio;

    if (camHeight < height) {
        newHeightRatio = (float) height / (float) mPreviewSize.height;
        newCamHeight = (newHeightRatio * camHeight);
        Log.e(TAG, camHeight + " " + height + " " + mPreviewSize.height + " " + newHeightRatio + " " + newCamHeight);
        setMeasuredDimension((int) (width * newHeightRatio), (int) newCamHeight);
        Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | H_ratio - " + newHeightRatio + " | A_width - " + (width * newHeightRatio) + " | A_height - " + newCamHeight);
    } else {
        newCamHeight = camHeight;
        setMeasuredDimension(width, (int) newCamHeight);
        Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | A_width - " + (width) + " | A_height - " + newCamHeight);
    }

화면 높이를 계산하고 화면 높이와 mPreviewSize 높이의 비율을 가져옵니다. 그런 다음 카메라의 너비와 높이에 새로운 높이 비율을 곱하고 그에 따라 측정 된 치수를 설정합니다.

여기에 이미지 설명을 입력하십시오

그리고 다음으로 아는 것은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

이것은 전면 카메라에서도 잘 작동합니다. 이것이 가장 좋은 방법이라고 생각합니다. 이제 내 앱에 남은 것은 “캡처”를 클릭하면 미리보기 자체를 저장하는 것입니다. 하지만 나중에 요.


답변

좋아, 그래서 일반적인 카메라 미리보기 스트레칭 문제에 대한 충분한 대답이 없다고 생각 합니다. 아니면 적어도 하나를 찾지 못했습니다. 내 응용 프로그램은이 스트레칭 증후군을 겪었고이 포털과 인터넷의 모든 사용자 답변에서 솔루션을 함께 모으는 데 시간이 걸렸습니다.

@Hesam의 솔루션을 시도했지만 작동하지 않아 카메라 미리보기가 크게 왜곡되었습니다.

먼저 솔루션의 코드 (코드의 중요한 부분)를 보여준 다음 왜 그 단계를 수행했는지 설명합니다. 성능 수정의 여지가 있습니다.

주요 활동 XML 레이아웃 :

<RelativeLayout
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
    />
</RelativeLayout>

카메라 미리보기 :

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

private SurfaceHolder prHolder;
private Camera prCamera;
public List<Camera.Size> prSupportedPreviewSizes;
private Camera.Size prPreviewSize;

@SuppressWarnings("deprecation")
public YoCameraPreview(Context context, Camera camera) {
    super(context);
    prCamera = camera;

    prSupportedPreviewSizes = prCamera.getParameters().getSupportedPreviewSizes();

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

public void surfaceCreated(SurfaceHolder holder) {
    try {
        prCamera.setPreviewDisplay(holder);
        prCamera.startPreview();
    } catch (IOException e) {
        Log.d("Yologram", "Error setting camera preview: " + e.getMessage());
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    if (prHolder.getSurface() == null){
      return;
    }

    try {
        prCamera.stopPreview();
    } catch (Exception e){
    }

    try {
        Camera.Parameters parameters = prCamera.getParameters();
        List<String> focusModes = parameters.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        }
        parameters.setPreviewSize(prPreviewSize.width, prPreviewSize.height);

        prCamera.setParameters(parameters);
        prCamera.setPreviewDisplay(prHolder);
        prCamera.startPreview();

    } catch (Exception e){
        Log.d("Yologram", "Error starting camera preview: " + e.getMessage());
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

    setMeasuredDimension(width, height);

    if (prSupportedPreviewSizes != null) {
        prPreviewSize =
            getOptimalPreviewSize(prSupportedPreviewSizes, width, height);
    }
}

public Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {

    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) h / w;

    if (sizes == null)
        return null;

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

    int targetHeight = h;

    for (Camera.Size size : 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);
        }
    }

    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }

    return optimalSize;
}
}

주요 활동:

public class MainActivity extends Activity {

...

@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

        maCamera = getCameraInstance();

        maLayoutPreview = (FrameLayout) findViewById(R.id.camera_preview);

        maPreview = new CameraPreview(this, maCamera);

        Point displayDim = getDisplayWH();
        Point layoutPreviewDim = calcCamPrevDimensions(displayDim,
                maPreview.getOptimalPreviewSize(maPreview.prSupportedPreviewSizes,
                    displayDim.x, displayDim.y));
        if (layoutPreviewDim != null) {
            RelativeLayout.LayoutParams layoutPreviewParams =
                (RelativeLayout.LayoutParams) maLayoutPreview.getLayoutParams();
            layoutPreviewParams.width = layoutPreviewDim.x;
            layoutPreviewParams.height = layoutPreviewDim.y;
            layoutPreviewParams.addRule(RelativeLayout.CENTER_IN_PARENT);
            maLayoutPreview.setLayoutParams(layoutPreviewParams);
        }
        maLayoutPreview.addView(maPreview);
}

@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
private Point getDisplayWH() {

    Display display = this.getWindowManager().getDefaultDisplay();
    Point displayWH = new Point();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
        display.getSize(displayWH);
        return displayWH;
    }
    displayWH.set(display.getWidth(), display.getHeight());
    return displayWH;
}

private Point calcCamPrevDimensions(Point disDim, Camera.Size camDim) {

    Point displayDim = disDim;
    Camera.Size cameraDim = camDim;

    double widthRatio = (double) displayDim.x / cameraDim.width;
    double heightRatio = (double) displayDim.y / cameraDim.height;

    // use ">" to zoom preview full screen
    if (widthRatio < heightRatio) {
        Point calcDimensions = new Point();
        calcDimensions.x = displayDim.x;
        calcDimensions.y = (displayDim.x * cameraDim.height) / cameraDim.width;
        return calcDimensions;
    }
    // use "<" to zoom preview full screen
    if (widthRatio > heightRatio) {
        Point calcDimensions = new Point();
        calcDimensions.x = (displayDim.y * cameraDim.width) / cameraDim.height;
        calcDimensions.y = displayDim.y;
        return calcDimensions;
    }
    return null;
}
}

내 논평 :

모든이의 요점은 당신이 계산되지만 있다는 것입니다 최적의 카메라 크기getOptimalPreviewSize()당신만을 선택 에 가장 가까운 비율 화면에 맞게합니다. 따라서 비율이 정확히 동일 하지 않으면 미리보기가 늘어납니다.

왜 늘어날까요? FrameLayout 카메라 미리보기는 layout.xml 에서 너비와 높이 가 match_parent 로 설정되어 있기 때문 입니다. 그래서 미리보기가 전체 화면으로 확대됩니다.

수행 할 작업은 선택한 카메라 크기 비율 에 맞게 카메라 미리보기 레이아웃 너비와 높이 를 설정 하여 미리보기가 가로 세로 비율을 유지하고 왜곡되지 않도록하는 것입니다.

CameraPreview클래스 를 사용하여 모든 계산 및 레이아웃 변경을 시도했지만 이해할 수 없었습니다. 나는 적용하려고 이 솔루션을 하지만, SurfaceView인식하지 못 getChildCount ()하거나 getChildAt (int index). 나는 결국에 대한 참조로 작동한다고 생각 maLayoutPreview했지만 잘못 작동하여 전체 응용 프로그램에 설정된 비율을 적용했으며 첫 번째 사진을 찍은 후 그렇게했습니다. 그래서 레이아웃을 수정하고 레이아웃 수정을MainActivity .

에서 CameraPreview내가 변경 prSupportedPreviewSizesgetOptimalPreviewSize()공공 난에서 사용할 수 있습니다 MainActivity. 그런 다음 디스플레이 크기 (탐색 / 상태 표시 줄이없는 경우)를 빼고 최적의 카메라 크기를 선택했습니다 . 디스플레이 크기 대신 RelativeLayout (또는 FrameLayout) 크기를 얻으려고했지만 0 값을 반환했습니다. 이 솔루션 은 저에게 효과적이지 않았습니다. 레이아웃은 가치가 있습니다.onWindowFocusChanged (로그에서 확인).

선택한 카메라 크기의 종횡비와 일치하도록 레이아웃 크기를 계산하는 방법이 있습니다. 이제 설정 만하면됩니다.LayoutParams 카메라 미리보기 레이아웃 됩니다. 너비, 높이를 변경하고 부모 중심에 배치하십시오.

미리보기 크기를 계산하는 방법에는 두 가지가 있습니다. 측면 또는 상단 / 하단에 검은 색 막대 (windowBackground가 null로 설정된 경우)가 있는 화면에 맞출 수 있습니다 . 또는 미리보기 를 전체 화면으로 확대 하고자합니다 . 에 더 많은 정보가 담긴 의견을 남겼습니다 calcCamPrevDimensions().


답변

안녕하세요 getOptimalPreview ()이 작동하지 않아서 버전을 공유하고 싶습니다.

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {

    if (sizes==null) return null;

    Camera.Size optimalSize = null;
    double ratio = (double)h/w;
    double minDiff = Double.MAX_VALUE;
    double newDiff;
    for (Camera.Size size : sizes) {
        newDiff = Math.abs((double)size.width/size.height - ratio);
        if (newDiff < minDiff) {
            optimalSize = size;
            minDiff = newDiff;
        }
    }
    return optimalSize;
}


답변

이 스레드를보다 완벽하게하기 위해 대답 버전을 추가하고 있습니다.

내가 달성하고 싶었던 것 : 표면보기를 늘려서는 안되며 화면 전체를 덮어야합니다. 또한 내 앱에는 가로 모드 만있었습니다.

해결책:

이 솔루션은 F1sher 솔루션에 대한 매우 작은 확장입니다.

=> 첫 번째 단계는 F1sher 솔루션을 통합하는 것입니다.

=> 이제 표면보기가 전체 화면을 덮지 않을 때 F1sher 솔루션에 시나리오가 발생할 수 있습니다. 해결책은 전체 화면을 덮을 수 있도록 표면보기를 화면 크기보다 크게 만드는 것입니다.

    size = getOptimalPreviewSize(mCamera.getParameters().getSupportedPreviewSizes(), screenWidth, screenHeight);

    Camera.Parameters parameters = mCamera.getParameters();
    parameters.setPreviewSize(size.width, size.height);


    mCamera.setParameters(parameters);

    double screenRatio = (double) screenHeight / screenWidth;
    double previewRatio = (double) size.height / size.width;

    if (previewRatio > screenRatio)     /*if preview ratio is greater than screen ratio then we will have to recalculate the surface height while keeping the surface width equal to the screen width*/
    {
        RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams(screenWidth, (int) (screenWidth * previewRatio));
        params1.addRule(RelativeLayout.CENTER_IN_PARENT);
        flPreview.setLayoutParams(params1);

        flPreview.setClipChildren(false);

        LayoutParams surfaceParams = new LayoutParams(screenWidth, (int) (screenWidth * previewRatio));
        surfaceParams.gravity = Gravity.CENTER;
        mPreview.setLayoutParams(surfaceParams);
    }
    else     /*if preview ratio is smaller than screen ratio then we will have to recalculate the surface width while keeping the surface height equal to the screen height*/
    {
        RelativeLayout.LayoutParams params1 = new RelativeLayout.LayoutParams((int) ((double) screenHeight / previewRatio), screenHeight);
        params1.addRule(RelativeLayout.CENTER_IN_PARENT);
        flPreview.setLayoutParams(params1);
        flPreview.setClipChildren(false);

        LayoutParams surfaceParams = new LayoutParams((int) ((double) screenHeight / previewRatio), screenHeight);
        surfaceParams.gravity = Gravity.CENTER;
        mPreview.setLayoutParams(surfaceParams);

    }

    flPreview.addView(mPreview);

  /*  The TopMost layout used is the RelativeLayout, flPreview is the FrameLayout in which Surface View is added, mPreview is an instance of a class which extends SurfaceView  */


답변

문제가 무엇인지 알아 냈습니다 . 방향이 변경되었습니다. 카메라 방향을 90도 또는 270 도로 변경하면 너비와 높이교체 해야합니다 지원되는 크기의 하며 모두 정상입니다.

또한 표면보기는 프레임 레이아웃에 있어야하며 중심 중력을 가져야합니다.

다음은 C # (Xamarin)에 대한 예입니다.

public void SurfaceChanged(ISurfaceHolder holder, Android.Graphics.Format format, int width, int height)
{
    _camera.StopPreview();

    // find best supported preview size

    var parameters = _camera.GetParameters();
    var supportedSizes = parameters.SupportedPreviewSizes;
    var bestPreviewSize = supportedSizes
        .Select(x => new { Width = x.Height, Height = x.Width, Original = x }) // HACK swap height and width because of changed orientation to 90 degrees
        .OrderBy(x => Math.Pow(Math.Abs(x.Width - width), 3) + Math.Pow(Math.Abs(x.Height - height), 2))
        .First();

    if (height == bestPreviewSize.Height && width == bestPreviewSize.Width)
    {
        // start preview if best supported preview size equals current surface view size

        parameters.SetPreviewSize(bestPreviewSize.Original.Width, bestPreviewSize.Original.Height);
        _camera.SetParameters(parameters);
        _camera.StartPreview();
    }
    else
    {
        // if not than change surface view size to best supported (SurfaceChanged will be called once again)

        var layoutParameters = _surfaceView.LayoutParameters;
        layoutParameters.Width = bestPreviewSize.Width;
        layoutParameters.Height = bestPreviewSize.Height;
        _surfaceView.LayoutParameters = layoutParameters;
    }
}

카메라 매개 변수는 원본 크기 (스왑되지 않음)로 설정해야하고 표면보기 크기는 교체해야합니다.