Android visualiza la transformación de rotación 3D en pantallas de gran resolución

Estoy implementando la animación del tirón de la tarjeta 3d para android (api> 14) y tengo un problema con las tabletas de pantalla grande (> 2048 dpi). Durante la investigación del problema he llegado al siguiente bloque básico:

Trató de transformar una vista (simple ImageView) utilizando la matriz y rotateY de la cámara por algún ángulo y funciona bien para ángulo <60 y ángulo> 120 (transformado y visualizado) pero la imagen desaparece (no se muestra) cuando el ángulo está entre 60 y 120. Aquí está el código que uso:

private void applyTransform(float degree) { float [] values = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}; float centerX = image1.getMeasuredWidth() / 2.0f; float centerY = image1.getMeasuredHeight() / 2.0f; Matrix m = new Matrix(); m.setValues(values); Camera camera = new Camera(); camera.save(); camera.rotateY(degree); camera.getMatrix(m); camera.restore(); m.preTranslate(-centerX, -centerY); // 1 draws fine without these 2 lines m.postTranslate(centerX, centerY); // 2 image1.setImageMatrix(m); } 

Y aquí está mi XML de la disposición

  <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/ImageView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/naponer" android:clickable="true" android:scaleType="matrix"> </ImageView> </FrameLayout> 

Así que tengo los siguientes casos:

  • Funciona bien para cualquier ángulo, cualquier punto central si se ejecuta en pequeñas pantallas 800X480, 1024×720, etc …
  • Funciona bien para ángulo <60 y> 120 cuando se ejecuta en dispositivos de pantalla grande 2048×1536, 2560×1600 …
  • Funciona bien para cualquier ángulo en cualquier dispositivo si la rotación no está centrada (antes y después de las traducciones de la matriz comentada)
  • Falla (la imagen desaparece) cuando se ejecuta en el dispositivo de pantalla grande, la rotación centrada y el ángulo está entre 60 y 120 grados.

Por favor, dígale lo que estoy haciendo mal y aconsejar alguna solución … gracias !!!

Este problema se debe a la distancia de la cámara utilizada para calcular la transformación. Aunque la clase Camera no dice mucho sobre el tema, se explica mejor en la documentación del método View.setCameraDistance() (énfasis mío):

Define la distancia a lo largo del eje Z (ortogonal al plano X / Y en el que se dibujan las vistas) de la cámara a esta vista. La distancia de la cámara afecta a las transformaciones 3D, por ejemplo rotaciones alrededor del eje X e Y. (…)

La distancia de la cámara respecto al plano de vista puede afectar a la distorsión en perspectiva de la vista cuando se gira alrededor del eje x o y. Por ejemplo, una gran distancia dará lugar a un gran ángulo de visión, y no habrá mucha distorsión de perspectiva de la vista a medida que gira. Una distancia corta puede causar distorsión mucho más perspectiva tras la rotación, y también puede resultar en algunos artefactos de dibujo si la vista girada termina parcialmente detrás de la cámara (razón por la cual la recomendación es utilizar una distancia al menos tan grande como el tamaño de la Vista, si se va a girar la vista.)

Para ser honesto, no había visto este efecto en particular (no dibujar en absoluto) antes, pero sospeché que podría estar relacionado con esta cuestión relacionada con la distorsión de perspectiva que había encontrado en el pasado. 🙂

Por lo tanto, la solución es utilizar el método Camera.setLocation() para garantizar que esto no suceda.

Una distinción importante con el método View.setCameraDistance() es que las unidades no son las mismas , ya que setLocation() no utiliza píxeles. Mientras setCameraDistance() ajusta para la densidad, setLocation() no. Por lo tanto, si desea calcular una distancia z apropiada en función de las dimensiones de la vista , recuerde ajustar la densidad. Por ejemplo:

 float cameraDistance = Math.max(image1.getMeasuredHeight(), image1.getMeasuredWidth()) * 5; float densityDpi = getResources().getDisplayMetrics().densityDpi; camera.setLocation(0, 0, -cameraDistance / densityDpi); 

En lugar de utilizar 12 líneas para crear la matriz de rotación, sólo podría implementar este en primera línea http://en.wikipedia.org/wiki/Rotation_matrix

Dependiendo del efecto que desee, es posible que desee centralizar la imagen en el eje que desea girar. http://en.wikipedia.org/wiki/Transformation_matrix

Hmm para la desaparición de la imagen, me imagino que tiene algo que ver con la memoria (fuera de la memoria – aunque esto traería excepción) o problemas de redondeo. Tal vez usted podría tratar de aumentar la precisión de doble precisión?

Una cosa que viene a la mente es que cos (alfa) va hacia 0 cuando alfa va hacia PI / 2. Aparte de eso, no veo ninguna correlación entre los ángulos y por qué no funciona para grandes imágenes.

Debe ajustar las coordenadas de Translate. Al calcular la traducción de su imagen también debe tener en cuenta el tamaño de la imagen. Cuando se realizan cálculos matriciales se establece android:scaleType="matrix" para su ImageView . Esto alinea su imagen en la esquina superior izquierda de forma predeterminada. Luego, cuando apliques tu traducción pre / post, tu imagen puede salir de los límites de tu ImageView (especialmente si el ImageView es relativamente grande y tu imagen es relativamente pequeña, como en el caso de tabletas de pantalla beeg).

La siguiente traducción da como resultado la rotación de la imagen alrededor de su eje central Y y mantiene la imagen alineada en la esquina superior izquierda:

 m.preTranslate(-imageWidth/2, 0); m.postTranslate(imageWidth/2, 0); 

La siguiente alternativa da lugar a que la imagen se haga girar alrededor de su eje central Y / X y alinee la imagen con el centro del ImageView :

 m.preTranslate(-imageWidth/2, -imageHeight/2); m.postTranslate(centerX, centerY); 

Si su imagen es un mapa de bits, puede utilizar anchura / altura intrínseca:

 Drawable drawable = image1.getDrawable(); imageHeight = drawable.getIntrinsicHeight(); imageWidth = drawable.getIntrinsicWidth(); 
  • Lienzo dirección drawtext
  • ¿Cómo desactivar la rotación en modo horizontal?
  • Cómo crear una imagen giratoria controlada por gestos para una interfaz de usuario
  • Widget Android ImageButton pierde imagen cuando se gira la pantalla
  • Cómo rotar un mapa de bits en Android acerca de imágenes de forma suave sin movimiento oscilatorio
  • Cómo evitar reiniciar la actividad cuando cambia la orientación en Android
  • Cómo rotar Bitmap sin crear uno nuevo?
  • Android: los mapas de bits cargados desde la galería se giran en ImageView
  • Cómo usar los datos del sensor onSensorChanged en combinación con OpenGL
  • Rotación del videobuffer real en Videoview
  • Android: Manejo eficiente de la rotación de la pantalla
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.