He estado trabajando para hacer mi actividad de cámara personalizada en Android, pero al girar la cámara, la relación de aspecto de la vista de la superficie se confunde.
En mi creación de la actividad, configuré el framelayout que contiene la vista de superficie que muestra los parámetros de la cámara.
//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);
Luego, en la vista de superficie, configuro los parámetros de la cámara para que se muestren
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();
}
}
Puedes ver que el hombre LEGO se hace más alto y más delgado cuando se gira el teléfono:
¿Cómo puedo asegurarme de que la relación de aspecto para la vista de mi cámara sea correcta?
android
android-camera
surfaceview
preview
aspect-ratio
Scientiffic
fuente
fuente
Respuestas:
Estoy usando este método -> basado en Demos API para obtener mi Tamaño de vista previa:
Como puede ver, debe ingresar el ancho y la altura de su pantalla. Este método calculará la relación de pantalla en función de esos valores y luego, de la lista de tamaños de vista previa admitidos, elegirá el mejor para usted de los disponibles. Obtenga su lista SupportPreviewSize en el lugar donde el objeto Camera no es nulo utilizando
Y luego en onMeasure puede obtener su vista previa óptima Tamaño así:
Y luego (en mi código en el método SurfaceChanged, como dije que estoy usando la estructura API Demos del código CameraActivity, puede generarlo en Eclipse):
Y una pista para ti, porque hice casi la misma aplicación que tú. Una buena práctica para Camera Activity es ocultar StatusBar. Aplicaciones como Instagram lo están haciendo. Reduce el valor de altura de la pantalla y cambia el valor de la relación. Es posible obtener tamaños de vista previa extraños en algunos dispositivos (su SurfaceView se reducirá un poco)
Y para responder a su pregunta, ¿cómo verificar si su relación de vista previa es correcta? Luego obtenga el alto y el ancho de los parámetros que configuró:
su relación establecida es igual a la altura / ancho. Si desea que la cámara se vea bien en su pantalla, la relación altura / ancho de los parámetros que configure en la cámara debe ser la misma que la relación altura (menos la barra de estado) / ancho de la pantalla.
fuente
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height)
.La solución de F1Sher es buena pero a veces no funciona. Particularmente, cuando su SurfaceView no cubre toda la pantalla. En este caso, debe anular el método onMeasure (). He copiado mi código aquí para su referencia.
Como medí SurfaceView en función del ancho, tengo un pequeño espacio en blanco al final de la pantalla que lo llené por diseño. Puede solucionar este problema si mantiene la altura y aumenta el ancho multiplicándolo por la relación. Sin embargo, aplastará ligeramente SurfaceView.
fuente
getOptimalPreviewSize
para que esto funcionara para mí. ¿Es esto porque la orientación de la pantalla se estableció en 90? De lo contrario, los cálculos de la relación se ni siquiera cerca (objetivo era 1,7 y la relación de la cámara eran menos de 1)NOTA: MI SOLUCIÓN ES UNA CONTINUACIÓN DE LA SOLUCIÓN DE HESAM: https://stackoverflow.com/a/22758359/1718734
Lo que abordo: Hesam dijo que hay un pequeño espacio en blanco que puede aparecer en algunos teléfonos, como este:
Hesam sugirió una segunda solución, pero eso aplasta la vista previa. Y en algunos dispositivos, distorsiona mucho.
Entonces, ¿cómo solucionamos este problema? Es simple ... multiplicando las relaciones de aspecto hasta que llene la pantalla. He notado que varias aplicaciones populares como Snapchat, WhatsApp, etc. funcionan de la misma manera.
Todo lo que tiene que hacer es agregar esto al método onMeasure:
Esto calculará la altura de la pantalla y obtendrá la relación entre la altura de la pantalla y la altura mPreviewSize. Luego, multiplica el ancho y la altura de la cámara por la nueva relación de altura y establece la dimensión medida en consecuencia.
Y lo siguiente que sabes es que terminas con esto: D
Esto también funciona bien con la cámara frontal. Creo que esta es la mejor manera de hacerlo. Ahora lo único que queda para mi aplicación es guardar la vista previa al hacer clic en "Capturar". Pero ya, esto es todo.
fuente
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
método siempre obtengo ancho = 0 y altura = 0;De acuerdo, creo que no hay una respuesta suficiente para el problema general de estiramiento de la vista previa de la cámara. O al menos no encontré uno. Mi aplicación también sufrió este síndrome de estiramiento y me tomó un tiempo encontrar una solución de todas las respuestas de los usuarios en este portal e Internet.
Intenté la solución de @ Hesam pero no funcionó y dejé la vista previa de mi cámara muy distorsionada.
Primero muestro el código de mi solución (las partes importantes del código) y luego explico por qué tomé esos pasos. Hay espacio para modificaciones de rendimiento.
Diseño xml de actividad principal:
Vista previa de la cámara:
Actividad principal:
Mi comentario:
El punto de todo esto es, que si bien se calcula el tamaño de la cámara óptima en
getOptimalPreviewSize()
sólo recoger la relación más cercana para adaptarse a su pantalla. Entonces, a menos que la relación sea exactamente la misma, la vista previa se extenderá.¿Por qué se estirará? Porque la vista previa de su cámara FrameLayout está configurada en layout.xml para emparejar_parent en ancho y alto. Por eso, la vista previa se extenderá a pantalla completa.
Lo que debe hacerse es establecer el ancho y la altura del diseño de la vista previa de la cámara para que coincida con la relación de tamaño de la cámara elegida , de modo que la vista previa mantenga su relación de aspecto y no se distorsione.
Traté de usar la
CameraPreview
clase para hacer todos los cálculos y cambios de diseño, pero no pude resolverlo. Traté de aplicar esta solución , peroSurfaceView
no reconocegetChildCount ()
ogetChildAt (int index)
. Creo que finalmente lo hice funcionar con una referencia amaLayoutPreview
, pero se estaba comportando mal y apliqué la proporción establecida a toda mi aplicación y lo hizo después de tomar la primera fotografía. Así que lo dejé pasar y moví las modificaciones de diseño alMainActivity
.En
CameraPreview
CambiéprSupportedPreviewSizes
ygetOptimalPreviewSize()
en público para poder usarloMainActivity
. Luego necesitaba las dimensiones de la pantalla (menos la barra de navegación / estado si hay una) y elegí el tamaño óptimo de la cámara . Intenté obtener el tamaño RelativeLayout (o FrameLayout) en lugar del tamaño de visualización, pero estaba devolviendo un valor cero. Esta solución no me funcionó. El diseño obtuvo su valor despuésonWindowFocusChanged
(marcado en el registro).Así que tengo mis métodos para calcular las dimensiones del diseño para que coincidan con la relación de aspecto del tamaño de cámara elegido. Ahora solo necesita configurar
LayoutParams
el diseño de vista previa de su cámara. Cambie el ancho, la altura y céntrelo en padre.Hay dos opciones para calcular las dimensiones de la vista previa. O desea que se ajuste a la pantalla con barras negras (si windowBackground está configurado como nulo) en los lados o arriba / abajo. O desea que la vista previa se amplíe a pantalla completa . Dejé un comentario con más información en
calcCamPrevDimensions()
.fuente
Hola, el getOptimalPreview () que está aquí no funcionó para mí, así que quiero compartir mi versión:
fuente
Solo para hacer este hilo más completo, estoy agregando mi versión de respuesta:
Lo que quería lograr: la vista de superficie no debería extenderse, y debería cubrir toda la pantalla. Además, solo había un modo horizontal en mi aplicación.
Solución:
La solución es una extensión extremadamente pequeña de la solución de F1sher:
=> El primer paso es integrar la solución de F1sher.
=> Ahora, puede surgir un escenario en la solución de F1sher cuando la vista de superficie no cubre toda la pantalla, la solución es hacer que la vista de superficie sea mayor que las dimensiones de la pantalla para que cubra toda la pantalla, para eso:
fuente
Descubrí cuál es el problema: es con los cambios de orientación . Si cambia la orientación de la cámara a 90 o 270 grados, debe cambiar el ancho y la altura de los tamaños admitidos y todo estará bien.
También la vista de la superficie debe estar en un diseño de marco y tener un centro de gravedad.
Aquí hay un ejemplo en C # (Xamarin):
Tenga en cuenta que los parámetros de la cámara deben establecerse como tamaño original (no intercambiados) y el tamaño de la vista de superficie debe intercambiarse.
fuente
Intenté toda la solución anterior pero ninguna de ellas funciona para mí. Finalmente lo resolví yo mismo, y encuentro que en realidad es bastante fácil. Hay dos puntos que debes tener cuidado.
Este tamaño de vista previa debe ser una de las resoluciones compatibles con la cámara, que se puede obtener de la siguiente manera:
generalmente uno de rawSupportedSize equivale a la resolución del dispositivo.
En segundo lugar, coloque su SurfaceView en FrameLayout y configure la altura y el ancho del diseño de la superficie en el método SurfaceChanged como se indicó anteriormente
Ok, ya está hecho, espero que esto pueda ayudarte.
fuente
Mis requisitos son que la vista previa de la cámara debe ser de pantalla completa y mantener la relación de aspecto. La solución de Hesam y Yoosuf fue excelente, pero veo un problema de zoom alto por alguna razón.
La idea es la misma, tener el centro del contenedor de vista previa en padre y aumentar el ancho o la altura dependen de las relaciones de aspecto hasta que pueda cubrir toda la pantalla.
Una cosa a tener en cuenta es que el tamaño de la vista previa es horizontal porque configuramos la orientación de la pantalla.
El contenedor al que agregaremos la vista SurfaceView:
Agregue la vista previa a su contenedor con el centro en padre en su actividad.
Dentro de la clase CameraPreview:
fuente
Debe establecer cameraView.getLayoutParams (). Height y cameraView.getLayoutParams (). Width según la relación de aspecto que desee.
fuente
Renuncié a los cálculos y simplemente obtuve el tamaño de la vista donde quiero que se muestre la vista previa de la cámara y configuré el mismo tamaño de vista previa de la cámara (solo volteo / ancho debido a la rotación) en mi implementación personalizada de SurfaceView:
fuente