Preguntados a menudo, nunca respondidos (al menos no de forma 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 de ImageView para reflejar la altura proporcionalmente correcta de la imagen.
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
Esto da como resultado la imagen centrada en su tamaño original (más pequeño que el ancho de la pantalla) con márgenes a los lados. No es bueno.
Así que agregué
android:adjustViewBounds="true"
Mismo efecto, nada bueno. yo añadí
android:scaleType="centerInside"
Mismo efecto, no es bueno. Me cambié centerInside
a fitCenter
. Mismo efecto, nada bueno. Me cambié centerInside
a 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 me cambié centerCrop
a fitXY
.
android:scaleType="fitXY"
Ahora la imagen se escala al ancho de la pantalla pero no en el eje y, lo que resulta en una imagen distorsionada .
Eliminar android:adjustViewBounds="true"
no tiene ningún efecto. Agregar un android:layout_gravity
, como se sugiere en otra parte, nuevamente no tiene ningún efecto.
He probado otras combinaciones, sin éxito. Entonces, por favor, ¿alguien sabe?
¿Cómo se configura el XML de un ImageView para llenar el ancho de la pantalla, escalar una imagen más pequeña para llenar la vista completa, mostrando la imagen con su relación de aspecto sin distorsión ni recorte?
EDITAR: También intenté establecer una altura numérica arbitraria. Esto solo tiene efecto con la centerCrop
configuración. Distorsionará la imagen verticalmente según la altura de la vista.
fuente
android:scaleType="fitCenter"
?Respuestas:
Resolví esto creando una clase java que incluyes en tu archivo de diseño:
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, usa esto agregando tu clase a tu 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>
fuente
Tuve el mismo problema que el tuyo. Después de 30 minutos de probar diferentes variaciones, resolví el problema de esta manera. Le da la altura flexible y el ancho ajustado al ancho principal
<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" />
fuente
No existe una solución viable dentro del estándar de diseño XML.
La única forma confiable de reaccionar a un tamaño de imagen dinámico es usar
LayoutParams
en código.Decepcionante.
fuente
android:scaleType="fitCenter"
Calcule una escala que mantendrá la relación de aspecto original de src, pero también garantizará que src se ajuste completamente dentro de dst. Al menos un eje (X o Y) encajará exactamente. El resultado se centra dentro de dst.
editar:
El problema aquí es que
layout_height="wrap_content"
no está "permitiendo" que la imagen se expanda. Tendrás que establecer un tamaño para ello, para ese cambioandroid:layout_height="wrap_content"
a
android:layout_height="100dp" // or whatever size you want it to be
edit2:
funciona bien:
<ImageView android:id="@+id/imageView1" android:layout_width="match_parent" android:layout_height="300dp" android:scaleType="fitCenter" android:src="@drawable/img715945m" />
fuente
Esta es una pequeña adición a la excelente solución de Mark Martinsson.
Si el ancho de su imagen es mayor que su altura, la solución de Mark dejará espacio en la parte superior e inferior de la pantalla.
Lo siguiente corrige esto comparando primero el ancho y el alto: si el ancho de la imagen> = alto, entonces escalará el alto para que coincida con el alto de la pantalla, y luego escalará el ancho para preservar la relación de aspecto. De manera similar, si la altura de la imagen> ancho, escalará el ancho para que coincida con el ancho de la pantalla y luego escalará 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
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 u horizontal. Lo hace referencia en su diseño tal como 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" />
fuente
Me encontré con el mismo problema, pero con una altura fija, el ancho escalado manteniendo la relación de aspecto original de la imagen. Lo resolví mediante un diseño lineal ponderado. Con suerte, puede modificarlo según 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>
fuente
Versión de Kotlin de la respuesta de Mark Martinsson :
class DynamicImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val drawable = this.drawable if (drawable != null) { //Ceil not round - avoid thin vertical gaps along the left/right edges val width = View.MeasureSpec.getSize(widthMeasureSpec) val height = Math.ceil((width * drawable.intrinsicHeight.toFloat() / drawable.intrinsicWidth).toDouble()).toInt() this.setMeasuredDimension(width, height) } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec) } }
fuente
Una adición más a la solución de Mark Matinsson. Descubrí que algunas de mis imágenes estaban sobreescaladas que otras. Entonces modifiqué la clase para que la imagen se escala en un factor máximo. Si la imagen es demasiado pequeña para escalarla al ancho máximo sin volverse 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); } } }
fuente