Vista previa de la cámara se extendió en pocos dispositivos Android

Estoy haciendo una cámara personalizada como “SnapChat” para una aplicación de Android, pero la vista previa de la cámara se extiende en pocos dispositivos como (Moto g de segunda generación, uno + uno) pero no en (Samsung s3, Samsung s4). He usado la siguiente referencia La pantalla / vista previa de la cámara en pantalla completa no mantiene la relación de aspecto: la imagen está torcida, estirada para que quepa en la pantalla . Pero esto no me ayuda al 100%. Estoy compartiendo la pantalla.

La imagen estirada en Samsung Moto G de segunda generación es. enter image description hereenter image description here

Las imágenes de Samsung S3 que no se extienden están por encima

private void setPreviewLayout() { if (null == mCamera) { return; } Camera.Parameters parameters = null; Camera.Size size = null; try { int screenWidth = (int) getResources().getDisplayMetrics().widthPixels; int screenHeight = (int) getResources().getDisplayMetrics().heightPixels; parameters = mCamera.getParameters(); size = getOptimalPreviewSize(mCamera.getParameters().getSupportedPreviewSizes(), screenWidth, screenHeight); if (size != null) { parameters.setPreviewSize(size.width, size.height); } parameters.setPictureSize(screenHeight, screenWidth); ; mCamera.setParameters(parameters); if (on && currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) { parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON); } else { parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); } parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO); parameters.setExposureCompensation(0); parameters.setPictureFormat(ImageFormat.JPEG); parameters.setJpegQuality(100); List focusModes = parameters.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); } else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); } mCamera.setParameters(parameters); /* * camera.setPreviewDisplay(surfaceHolder); camera.startPreview(); */ } catch (Exception e) { e.printStackTrace(); } } private Camera.Size getOptimalPreviewSize(List 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; } 

Usar getOptimalPreviewSize() es importante, pero no resuelve todos los estiramientos en todos los dispositivos en todos los diseños. Debe estar preparado para recortar la vista previa un poco para que la vista previa llene la pantalla sin distorsión.

Existen diferentes técnicas para forzar el tamaño de la superficie diferente del tamaño real de la pantalla, pero esta es la más fácil:

Agrego el CameraView a mi diseño:

 public class CameraView extends SurfaceView implements SurfaceHolder.Callback { public CameraView(Context context, AttributeSet attr) { super(context, attr); // install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. getHolder().addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { openCamera(); bCameraInitialized = false; } @Override public void surfaceDestroyed(SurfaceHolder holder) { camera.release(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (bCameraInitialized) { // we will get here after we have resized the surface, see below return; } cameraSetup(w, h); bCameraInitialized = true; } private void cameraSetup(int w, int h) { // set the camera parameters, including the preview size FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); double cameraAspectRatio = ((double)optimalSize.width)/optimalSize.height; if (((double)h)/w > cameraAspectRatio) { lp.width = (int)(h/cameraAspectRatio+0.5); lp.height = h; } else { lp.height = (int)(w*cameraAspectRatio + 0.5); lp.width = w; lp.topMargin = (h - lp.height)/2; } lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; setLayoutParams(lp); requestLayout(); } 

Para enfatizar la idea principal, no incluí el manejo de errores, y no mostré aquí cómo la cámara realmente se inicia con un Looper secundario .

Debe anular el método onMeasure de la clase SurfaceView para obtener el ancho y la altura de la vista de superficie

 @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(mCamera.getParameters().getSupportedPreviewSizes(), width, height); } } 

A continuación, configure el tamaño de vista previa que tiene el tamaño de vista previa de los parámetros de la cámara.

 cameraParameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); mCamera.setParameters(cameraParameters); 

getSuggestedMinimumHeight (), getSuggestedMinimumWidth () son los métodos de la clase View

Espero que esto ayude !!!

prueba esto, está funcionando …

  public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private static final String TAG = "Camera Preview"; private static final double PREVIEW_SIZE_FACTOR = 3.00; private SurfaceHolder mHolder = null; private Camera mCamera = null; Camera.Parameters _parameters=null; @SuppressWarnings("deprecation") public CameraPreview(Context context, Camera camera) { super(context); mCamera = camera; // 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) { // The Surface has been created, now tell the camera where to draw the preview. try { Camera.Parameters parameters = mCamera.getParameters(); final Size mPreviewSize = getOptimalSize(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); mCamera.setParameters(parameters); mCamera.setPreviewDisplay(holder); mCamera.startPreview(); //startContinuousAutoFocus(); } catch (Exception e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { } @SuppressLint("NewApi") public void surfaceChanged(SurfaceHolder holder, int format, int w, int 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 // set Camera parameters // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } public void startPreview(){ try{ mCamera.startPreview(); }catch (Exception e) { } } private Size getOptimalSize() { Camera.Size result = null; final Camera.Parameters parameters = mCamera.getParameters(); Log.i(CameraPreview.class.getSimpleName(), "window width: " + getWidth() + ", height: " + getHeight()); for (final Camera.Size size : parameters.getSupportedPreviewSizes()) { if (size.width <= getWidth() * PREVIEW_SIZE_FACTOR && size.height <= getHeight() * PREVIEW_SIZE_FACTOR) { if (result == null) { result = size; } else { final int resultArea = result.width * result.height; final int newArea = size.width * size.height; if (newArea > resultArea) { result = size; } } } } if (result == null) { result = parameters.getSupportedPreviewSizes().get(0); } Log.i(CameraPreview.class.getSimpleName(), "Using PreviewSize: " + result.width + " x " + result.height); return result; } }