Intereting Posts
Android: автоматически выбирает debug / release Maps v2 api key? Admob: сбой приложений на Android 3.2 Android: получить элемент списка из кнопки, нажатой в пользовательском listview Проверьте, пуст ли EditText. Как скрыть / показать большой палец в SeekBar Внедрение графа множественного входного фильтра с библиотекой Libavfilter в Android NDK Android OCR tesseract: использование данных объектов Pixa для отображения ограничивающих прямоугольников Переменные переменных уровня приложения Android Как получить доступ к элементам пользовательского интерфейса в родительской активности из фрагмента Как обеспечить как аудиоданные, так и видеоданные MediaMux Как удалить разделитель из списка на Android? Android: как удалить элемент из спискаView и arrayAdapter Seem не получает ресурс Facebook SDK при использовании Facebook Android SDK в IntelliJ IDEA 12 Как правильно реализовать onRestoreInstanceState () для подкласса DialogPreference? Mylib.so имеет перестановки текста. Это трата памяти и представляет угрозу безопасности. Пожалуйста исправьте

Предварительный просмотр камеры в Android

Я работал над тем, чтобы сделать свою собственную работу с камерой на Android, но при повороте камеры соотношение сторон изображения поверхности становится испорченным.

В моем oncreate для деятельности я установил framelayout, который содержит поверхностное представление, которое отображает параметры камеры.

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

Затем в представлении «Поверхность» я устанавливаю параметры камеры для отображения

 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 становится более высоким и более тонким, когда телефон повернут:

Как я могу убедиться, что соотношение сторон изображения для камеры правильно?

Solutions Collecting From Web of "Предварительный просмотр камеры в Android"

Я использую этот метод -> на основе API Demos, чтобы получить свой размер предварительного просмотра:

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

Как вы можете видеть, вам нужно вводить ширину и высоту экрана. Этот метод будет вычислять коэффициент экрана на основе этих значений, а затем из списка поддерживаемых представлений PreviewSizes он выберет наилучшие для вас из доступных. Получите список поддерживаемыхPreviewSize, где объект Camera не равен нулю, используя

 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, как я уже сказал, я использую структуру API Demos кода CameraActivity, вы можете сгенерировать ее в Eclipse):

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

И один намек на вас, потому что я сделал почти такое же приложение, как вы. Хорошей практикой для деятельности камеры является скрытие StatusBar. Такие приложения, как Instagram, делают это. Это уменьшает значение высоты экрана и изменяет значение отношения. На некоторых устройствах можно получить странные размеры предварительного просмотра (ваш SurfaceView будет немного сокращен)


И чтобы ответить на ваш вопрос, как проверить правильность вашего коэффициента просмотра? Затем получите высоту и ширину параметров, которые вы установили:

 mCamera.setParameters(parameters); 

Ваше установленное соотношение равно высоте / ширине. Если вы хотите, чтобы камера выглядела хорошо на экране, соотношение высоты и ширины параметров, которые вы установили для камеры, должно быть таким же, как отношение высоты (минус состояние) / ширины экрана.

Решение F1Sher приятно, но иногда не работает. В частности, когда ваш поверхностный экран не охватывает весь экран. В этом случае вам необходимо переопределить метод onMeasure (). Я скопировал свой код здесь для справки.

Поскольку я измерил surfaceView по ширине, то у меня немного белый пробел в конце моего экрана, который я заполнил его по дизайну. Вы можете исправить эту проблему, если сохранить высоту и увеличить ширину, умножив ее на коэффициент. Тем не менее, он слегка пересушит поверхностьView.

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

ПРИМЕЧАНИЕ. МОЕ РЕШЕНИЕ – ПРОДОЛЖЕНИЕ РЕШЕНИЯ ХЕСАМА: https://stackoverflow.com/a/22758359/1718734

То, что я адресую: Хесем сказал, что на некоторых телефонах есть немного белого пространства, например:

ПРИМЕЧАНИЕ. Хотя соотношение сторон правильное, камера не заполняет весь экран.

Хесем предложил второе решение, но это преувеличивает предварительный просмотр. И на некоторых устройствах он сильно искажается.

Итак, как мы исправим эту проблему. Это просто … путем умножения пропорций до заполнения на экране. Я заметил, что несколько популярных приложений, таких как 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. Затем он умножает ширину и высоту камеры на новое отношение высоты и соответственно устанавливает измеренный размер.

Введите описание изображения здесь

И следующее, что вы знаете, вы в конечном итоге: D

Введите описание изображения здесь

Это также хорошо работает с фронтальной камерой. Я считаю, что это лучший способ сделать это. Теперь для моего приложения осталось только сохранить предварительный просмотр при нажатии на «Capture». Но я, вот и все.

Хорошо, поэтому я думаю, что нет достаточного ответа на общую проблему растяжения в предварительном просмотре камеры. Или, по крайней мере, я его не нашел. Мое приложение также пострадало от этого растягивающего синдрома, и мне потребовалось некоторое время, чтобы разобраться в решении всех ответов пользователей на этом портале и в Интернете.

Я попробовал решение @ 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 для соответствия ширине и высоте. Поэтому предварительный просмотр будет растянут до полного экрана.

Что нужно сделать, так это установить ширину и высоту предварительного просмотра предварительного просмотра камеры в соответствии с выбранным соотношением размеров камеры , поэтому предварительный просмотр сохраняет соотношение сторон и не искажается.

Я попытался использовать класс CameraPreview для выполнения всех вычислений и изменений макета, но я не мог понять это. Я попытался применить это решение , но SurfaceView не распознает getChildCount () или getChildAt (int index) . Я думаю, что в конечном итоге я работал с ссылкой на maLayoutPreview , но это было неправильным и применило коэффициент отношения ко всему моему приложению, и это было сделано после первого снимка. Поэтому я отпустил и переместил модификации макета в MainActivity .

В CameraPreview я изменил prSupportedPreviewSizes и getOptimalPreviewSize() для публики, поэтому я могу использовать его в MainActivity . Затем мне нужны размеры дисплея (минус панель навигации / состояния, если таковая имеется), и выберите оптимальный размер камеры . Я попытался получить размер RelativeLayout (или FrameLayout) вместо размера дисплея, но он возвращал нулевое значение. Это решение не сработало для меня. Макет получил его значение после onWindowFocusChanged ( onWindowFocusChanged в журнале).

Поэтому у меня есть методы расчета размеров макета в соответствии с соотношением сторон выбранного размера камеры. Теперь вам просто нужно установить LayoutParams в макет предварительного просмотра камеры. Измените ширину, высоту и центрируйте ее в родительском.

Как рассчитать размеры предварительного просмотра есть два варианта. Либо вы хотите, чтобы он соответствовал экрану с черными полосами (если windowBackground установлен на нуль) по бокам или сверху / снизу. Или вы хотите, чтобы предварительный просмотр был увеличен до полноэкранного режима . Я оставил комментарий с дополнительной информацией в 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 */ 

Вы должны установить для параметра cameraView.getLayoutParams () height и cameraView.getLayoutParams () ширину в соответствии с требуемым соотношением сторон.

Я понял, в чем проблема – это с изменениями ориентации . Если вы измените ориентацию камеры на 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; } } 

Обратите внимание, что параметры камеры должны быть установлены как исходный размер (не заменен), а размер поверхности должен быть заменен.

Я попробовал все решение выше, но ни один из них не работает для меня. Наконец, я решил это сам, и найти на самом деле все довольно просто. Есть два момента, которые вам нужно быть осторожными.

 parameters.setPreviewSize(cameraResolution.x, cameraResolution.y); 

Этот предварительный просмотр должен быть одним из поддерживаемых камерой разрешением, которое можно получить, как показано ниже:

 List<Camera.Size> rawSupportedSizes = parameters.getSupportedPreviewSizes(); 

Обычно один из rawSupportedSize равен разрешению устройства.

Во-вторых, поместите SurfaceView в FrameLayout и установите высоту и ширину поверхности в методе surfaceChanged, как указано выше

 FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) surfaceView.getLayoutParams(); layoutParams.height = cameraResolution.x; layoutParams.width = cameraResolution.y; 

Хорошо, все сделано, надеюсь, что это может вам помочь.

Мои требования: предварительный просмотр камеры должен быть полноэкранным и поддерживать соотношение сторон. Решение Hesam и Yoosuf было замечательным, но по какой-то причине я вижу проблему с высоким увеличением.

Идея такая же, иметь центр контейнера предварительного просмотра в родительском и увеличить ширину или высоту зависит от соотношения сторон, пока он не сможет покрыть весь экран.

Следует отметить, что размер предварительного просмотра в ландшафте, поскольку мы устанавливаем ориентацию дисплея.

camera.setDisplayOrientation (90);

Контейнер, который мы добавим в представление SurfaceView:

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

Добавьте предварительный просмотр в контейнер с центром в родительском объекте.

 this.cameraPreview = new CameraPreview(this, camera); cameraPreviewContainer.removeAllViews(); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); cameraPreviewContainer.addView(cameraPreview, 0, params); 

Внутри класса CameraPreview:

 @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 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 (holder.getSurface() == null) { // preview surface does not exist return; } stopPreview(); // set preview size and make any resize, rotate or // reformatting changes here try { Camera.Size nativePictureSize = CameraUtils.getNativeCameraPictureSize(camera); Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(optimalSize.width, optimalSize.height); parameters.setPictureSize(nativePictureSize.width, nativePictureSize.height); camera.setParameters(parameters); camera.setDisplayOrientation(90); camera.setPreviewDisplay(holder); camera.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 (supportedPreviewSizes != null && optimalSize == null) { optimalSize = CameraUtils.getOptimalSize(supportedPreviewSizes, width, height); Log.i(TAG, "optimal size: " + optimalSize.width + "w, " + optimalSize.height + "h"); } float previewRatio = (float) optimalSize.height / (float) optimalSize.width; // previewRatio is height/width because camera preview size are in landscape. float measuredSizeRatio = (float) width / (float) height; if (previewRatio >= measuredSizeRatio) { measuredHeight = height; measuredWidth = (int) ((float)height * previewRatio); } else { measuredWidth = width; measuredHeight = (int) ((float)width / previewRatio); } Log.i(TAG, "Preview size: " + width + "w, " + height + "h"); Log.i(TAG, "Preview size calculated: " + measuredWidth + "w, " + measuredHeight + "h"); setMeasuredDimension(measuredWidth, measuredHeight); } 

Я отказался от вычислений и просто получил размер представления, где я хочу, чтобы предварительный просмотр камеры отображался, и установите размер предварительного просмотра камеры одинаково (просто перевернутая ширина / высота из-за вращения) в моей пользовательской реализации SurfaceView:

 @Override // CameraPreview extends SurfaceView implements SurfaceHolder.Callback { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Display display = ((WindowManager) getContext().getSystemService( Context.WINDOW_SERVICE)).getDefaultDisplay(); if (display.getRotation() == Surface.ROTATION_0) { final Camera.Parameters params = camera.getParameters(); // viewParams is from the view where the preview is displayed params.setPreviewSize(viewParams.height, viewParams.width); camera.setDisplayOrientation(90); requestLayout(); camera.setParameters(params); } // I do not enable rotation, so this can otherwise stay as is }