mipmap - Android ImageView escala una imagen más pequeña al ancho con altura flexible sin recorte o distorsión
resize image android studio (8)
A menudo se pregunta, nunca responde (al menos no de una manera reproducible).
Tengo una vista de imagen con una imagen 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 hace que la imagen se centre en su tamaño original (más pequeño que el ancho de la pantalla) con márgenes laterales. No es bueno.
Así que agregué
android:adjustViewBounds="true"
Mismo efecto, no es bueno. yo añadí
android:scaleType="centerInside"
Mismo efecto, no es bueno. Cambié centerInside
al fitCenter
. Mismo efecto, no es bueno. Cambié centerInside
to 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
para fitXY
.
android:scaleType="fitXY"
Ahora la imagen se escala al ancho de la pantalla, pero no a escala en el eje y, lo que da como resultado una imagen distorsionada .
Eliminar android:adjustViewBounds="true"
no tiene ningún efecto. Agregar un android:layout_gravity
, como se sugiere en otro lugar, nuevamente no tiene efecto.
He intentado con otras combinaciones, fue en vano. 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 toda la vista, mostrar la imagen con su relación de aspecto sin distorsión o recorte?
EDITAR: También intenté establecer una altura numérica arbitraria. Esto solo tiene un efecto con la configuración centerCrop
. Distorsionará la imagen verticalmente según la altura de la vista.
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, entonces la solución de Mark dejará espacio en la parte superior e inferior de la pantalla.
Lo siguiente soluciona esto comparando primero el ancho y la altura: si el ancho de la imagen es> = alto, entonces escalará la altura para que coincida con la altura de la pantalla, y luego escalará el ancho para preservar la relación de aspecto. Del mismo modo, si la altura de la imagen es> ancho, entonces 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, cumple adecuadamente la definición de scaleType="centerCrop"
:
http://developer.android.com/reference/android/widget/ImageView.ScaleType.html
Escale la imagen uniformemente (mantenga la relación de aspecto de la imagen) para que ambas dimensiones (ancho y alto) de la imagen sean iguales o mayores que la dimensión correspondiente de la vista (menos el 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 u horizontal. Lo 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" />
Lo he resuelto 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 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>
Me encontré con el mismo problema, pero con una altura fija, ancho de escala manteniendo la relación de aspecto original de la imagen. Lo resolví a través de un diseño lineal ponderado. Con suerte puede modificarlo 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>
No hay 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 el código.
Decepcionante.
Tuve el mismo problema, como el tuyo. Después de 30 minutos de intentar variaciones difirent 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" />
Una adición más a la solución de Mark Matinsson. Descubrí que algunas de mis imágenes tenían más escala que otras. Así que modifiqué la clase para que la imagen se escalara por un factor máximo. Si la imagen es demasiado pequeña para escalar al máximo ancho 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);
}
}
}
Versión de Kotlin de la answer 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)
}
}
android:scaleType="fitCenter"
Calcule una escala que mantendrá la relación de aspecto src original, pero también asegurará que src se ajuste completamente dentro de dst. Al menos un eje (X o Y) se ajustará exactamente. El resultado se centra en 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 él, para ese cambio
android: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" />