Android ImageView escala la imagen más pequeña al ancho con altura flexible sin recortar ni distorsionar

A menudo se le pregunta, nunca responde (al menos no de una manera reproducible).

Tengo una vista de imagen con una imagen que es más pequeña que la vista. Quiero escalar la imagen al ancho de la pantalla y ajustar la altura del ImageView para reflejar la altura proporcionalmente correcta de la imagen.

<ImageView android:layout_width="fill_parent" android:layout_height="wrap_content" /> 

Esto resulta en la imagen centrada en su tamaño original (más pequeño que el ancho de la pantalla) con márgenes en el lado. No es bueno.

Así que agregué

 android:adjustViewBounds="true" 

El mismo efecto, no es bueno. yo añadí

 android:scaleType="centerInside" 

El mismo efecto, no es bueno. Cambié centerInside a fitCenter . El mismo efecto, no es bueno. Cambié centerInside al centerCrop .

 android:scaleType="centerCrop" 

Ahora, finalmente, la imagen se escala al ancho de la pantalla – ¡pero se recorta en la parte superior e inferior! Así que cambié centerCrop a fitXY .

 android:scaleType="fitXY" 

Ahora la imagen se escala al ancho de la pantalla pero no se escala en el eje y, lo que resulta en una imagen distorsionada .

Eliminar android:adjustViewBounds="true" no tiene efecto. Añadiendo un android:layout_gravity , como se sugiere en otro lugar, tiene de nuevo ningún efecto.

He intentado otras combinaciones – en vano. Por lo tanto, por favor alguien sabe:

¿Cómo se configura el XML de un ImageView para llenar el ancho de la pantalla, la escala de una imagen más pequeña para llenar toda la vista, la visualización de la imagen con su relación de aspecto sin distorsión o recorte?

EDIT: También intenté establecer una altura numérica arbitraria. Esto sólo tiene un efecto con el ajuste centerCrop . Deformará la imagen verticalmente de acuerdo con la altura de la vista.

He resuelto esto mediante la creación de una java-clase que se incluye en su layout-file:

 public class DynamicImageView extends ImageView { public DynamicImageView(final Context context, final AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { final Drawable d = this.getDrawable(); if (d != null) { // ceil not round - avoid thin vertical gaps along the left/right edges final int width = MeasureSpec.getSize(widthMeasureSpec); final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth()); this.setMeasuredDimension(width, height); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } } 

Ahora, utilice esto añadiendo su clase a su archivo de diseño:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <my.package.name.DynamicImageView android:layout_width="fill_parent" android:layout_height="wrap_content" android:scaleType="centerCrop" android:src="@drawable/about_image" /> </RelativeLayout> 

Tuve el mismo problema, como el tuyo. Después de 30 minutos de intentar variaciones difirent solucioné el problema de esta manera. Le da la altura flexible , y el ancho ajustado al ancho del padre

 <ImageView android:id="@+id/imageview_company_logo" android:layout_width="fill_parent" android:layout_height="fill_parent" android:adjustViewBounds="true" android:scaleType="fitCenter" android:src="@drawable/appicon" /> 

No existe una solución viable dentro del estándar de diseño XML.

La única forma fiable de reaccionar a un tamaño de imagen dinámico es utilizar LayoutParams en código.

Decepcionante.

  android:scaleType="fitCenter" 

Calcule una escala que mantenga la relación de aspecto src original, pero también asegurará que src se ajuste totalmente dentro de dst. Al menos un eje (X o Y) encajará exactamente. El resultado está centrado dentro de dst.

editar:

El problema aquí es que layout_height="wrap_content" no está "permitiendo" que la imagen se expanda. Usted tendrá que fijar un tamaño para él, para ese cambio

  android:layout_height="wrap_content" 

a

  android:layout_height="100dp" // or whatever size you want it to be 

Editar2:

funciona bien:

 <ImageView android:id="@+id/imageView1" android:layout_width="match_parent" android:layout_height="300dp" android:scaleType="fitCenter" android:src="@drawable/img715945m" /> 

Esta es una pequeña adición a la excelente solución de Mark Martinsson.

Si el ancho de la imagen es mayor que su altura, la solución de Mark dejará espacio en la parte superior e inferior de la pantalla.

Lo siguiente lo arregla comparando primero el ancho y la altura: si el ancho de la imagen> = altura, entonces escalará la altura para que coincida con la altura de la pantalla y, a continuación, escala el ancho para conservar la relación de aspecto. Del mismo modo, si la altura de la imagen> de ancho, a continuación, se escala el ancho para que coincida con el ancho de la pantalla y luego escala la altura para conservar la relación de aspecto.

En otras palabras, satisface adecuadamente la definición de scaleType="centerCrop" :

http://developer.android.com/reference/android/widget/ImageView.ScaleType.html

Escale uniformemente la imagen (mantenga la relación de aspecto de la imagen) de modo que ambas dimensiones (anchura y altura) de la imagen sean iguales o mayores que la dimensión correspondiente de la vista (menos relleno).

 package com.mypackage; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.ImageView; public class FixedCenterCrop extends ImageView { public FixedCenterCrop(final Context context, final AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { final Drawable d = this.getDrawable(); if(d != null) { int height = MeasureSpec.getSize(heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); if(width >= height) height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth()); else width = (int) Math.ceil(height * (float) d.getIntrinsicWidth() / d.getIntrinsicHeight()); this.setMeasuredDimension(width, height); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } } 

Esta solución funciona automáticamente en modo vertical o horizontal. Se hace referencia a ella en su diseño, al igual que lo hace en la solución de Mark. P.ej:

 <com.mypackage.FixedCenterCrop android:id="@+id/imgLoginBackground" android:src="@drawable/mybackground" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:scaleType="centerCrop" /> 

Me encontré con el mismo problema, pero con una altura fija, el ancho de escala manteniendo la relación de aspecto original de la imagen. Lo resolví mediante un diseño lineal ponderado. Se puede esperar que lo modifique para sus necesidades.

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/image" android:layout_width="0px" android:layout_height="180dip" android:layout_weight="1.0" android:adjustViewBounds="true" android:scaleType="fitStart" /> </LinearLayout> 

Una adición más a la solución de Mark Matinsson. Descubrí que algunas de mis imágenes estaban más escaladas que otras. Así que modifiqué la clase para que la imagen sea escalada por un factor máximo. Si la imagen es demasiado pequeña para ser escalada en el ancho máximo sin quedar borrosa, deja de escalar más allá del límite máximo.

 public class DynamicImageView extends ImageView { final int MAX_SCALE_FACTOR = 2; public DynamicImageView(final Context context) { super(context); } @Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { final Drawable d = this.getDrawable(); if (d != null) { // ceil not round - avoid thin vertical gaps along the left/right edges int width = View.MeasureSpec.getSize(widthMeasureSpec); if (width > (d.getIntrinsicWidth()*MAX_SCALE_FACTOR)) width = d.getIntrinsicWidth()*MAX_SCALE_FACTOR; final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth()); this.setMeasuredDimension(width, height); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } } 

}

  • Cómo añadir texto a ImageView en Android
  • Antialiased esquinas redondeadas en Android ImageView
  • Establecer visibilidad de la barra de progreso en la finalización de la carga de la imagen utilizando la biblioteca Glide
  • ¿Por qué ImageView.setImageURI () funcionaría en Android 2.2 pero no en 2.1?
  • ImageView: relleno horizontal manteniendo relación de aspecto
  • Imageview Roundcorner no funciona para las cuatro esquinas
  • Cómo obtener el ancho de imagen que se ha escalado
  • Android: OutofMemoryError: el tamaño de mapa de bits supera el presupuesto de VM sin ninguna razón que pueda ver
  • Obtener mapa de bits adjunto a ImageView
  • Android: cambiar el tamaño de la vista de la imagen en XML
  • Cómo animar ImageView de centro de cultivo para llenar la pantalla y viceversa (estilo de facebook)?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.