studio mipmap codepath adjust android imageview image-scaling

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" />