android - pantalla - Escala de imagen para llenar el ancho de ImageView y mantener la relación de aspecto
ajustar imagen a imageview android (14)
Esto no será aplicable si establece la imagen como fondo en ImageView, necesita establecer en src (android: src).
Gracias.
Tengo un GridView
. Los datos de GridView
se solicitan desde un servidor.
Aquí está el diseño del elemento en GridView
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/analysis_micon_bg"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingBottom="@dimen/half_activity_vertical_margin"
android:paddingLeft="@dimen/half_activity_horizontal_margin"
android:paddingRight="@dimen/half_activity_horizontal_margin"
android:paddingTop="@dimen/half_activity_vertical_margin" >
<ImageView
android:id="@+id/ranking_prod_pic"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@string/app_name"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/ranking_rank_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/ranking_prod_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/ranking_prod_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Solicito datos del servidor, obtengo la URL de la imagen y cargo la imagen en Bitmap
public static Bitmap loadBitmapFromInputStream(InputStream is) {
return BitmapFactory.decodeStream(is);
}
public static Bitmap loadBitmapFromHttpUrl(String url) {
try {
return loadBitmapFromInputStream((InputStream) (new URL(url).getContent()));
} catch (Exception e) {
Log.e(TAG, e.getMessage());
return null;
}
}
y está el código del getView(int position, View convertView, ViewGroup parent)
en el adaptador
Bitmap bitmap = BitmapUtil.loadBitmapFromHttpUrl(product.getHttpUrl());
prodImg.setImageBitmap(bitmap);
El tamaño de la imagen es 210*210
. Ejecuto mi aplicación en mi Nexus 4. La imagen llena el ancho de ImageView
, pero la altura de ImageView
no escala. ImageView
no muestra la imagen completa.
¿Cómo resuelvo este problema?
Hice algo similar a lo anterior y luego me golpeé la cabeza contra la pared durante unas horas porque no funcionó dentro de RelativeLayout
. Terminé con el siguiente código:
package com.example;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class ScaledImageView extends ImageView {
public ScaledImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final Drawable d = getDrawable();
if (d != null) {
int width;
int height;
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
height = MeasureSpec.getSize(heightMeasureSpec);
width = (int) Math.ceil(height * (float) d.getIntrinsicWidth() / d.getIntrinsicHeight());
} else {
width = MeasureSpec.getSize(widthMeasureSpec);
height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
}
setMeasuredDimension(width, height);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
Y luego, para evitar que RelativeLayout
ignore la dimensión medida, hice esto:
<FrameLayout
android:id="@+id/image_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/something">
<com.example.ScaledImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="150dp"/>
</FrameLayout>
Me gusta la respuesta de arnefm, pero cometió un pequeño error (ver comentarios) que trataré de corregir:
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* ImageView that keeps aspect ratio when scaled
*/
public class ScaleImageView extends ImageView {
public ScaleImageView(Context context) {
super(context);
}
public ScaleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScaleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
Drawable drawable = getDrawable();
if (drawable == null) {
setMeasuredDimension(0, 0);
} else {
int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
if (measuredHeight == 0 && measuredWidth == 0) { //Height and width set to wrap_content
setMeasuredDimension(measuredWidth, measuredHeight);
} else if (measuredHeight == 0) { //Height set to wrap_content
int width = measuredWidth;
int height = width * drawable.getIntrinsicHeight() / drawable.getIntrinsicWidth();
setMeasuredDimension(width, height);
} else if (measuredWidth == 0){ //Width set to wrap_content
int height = measuredHeight;
int width = height * drawable.getIntrinsicWidth() / drawable.getIntrinsicHeight();
setMeasuredDimension(width, height);
} else { //Width and height are explicitly set (either to match_parent or to exact value)
setMeasuredDimension(measuredWidth, measuredHeight);
}
}
} catch (Exception e) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
Por lo tanto, su ImageView
se escalará correctamente y no tendrá problemas de dimensión si (por ejemplo) se coloca dentro de ScrollView
Para crear una imagen con un ancho igual al ancho de la pantalla y una altura proporcionalmente establecida de acuerdo con la relación de aspecto, haga lo siguiente.
Glide.with(context).load(url).asBitmap().into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
// creating the image that maintain aspect ratio with width of image is set to screenwidth.
int width = imageView.getMeasuredWidth();
int diw = resource.getWidth();
if (diw > 0) {
int height = 0;
height = width * resource.getHeight() / diw;
resource = Bitmap.createScaledBitmap(resource, width, height, false);
}
imageView.setImageBitmap(resource);
}
});
Espero que esto ayude.
Prueba esto: resolvió el problema para mí
android:adjustViewBounds="true"
android:scaleType="fitXY"
Puede intentar hacer lo que hace manualmente cargando las imágenes, pero recomiendo encarecidamente echar un vistazo a Universal Image Loader .
Recientemente lo integé en mi proyecto y debo decir que es fantástico. ¿Te preocupa todo lo relacionado con hacer que las imágenes sean asíncronas, redimensionadas y almacenadas en caché por ti? Es muy fácil de integrar y configurar. Dentro de los 5 minutos, probablemente pueda hacerlo haciendo lo que quiera.
Código de ejemplo:
//ImageLoader config
DisplayImageOptions displayimageOptions = new DisplayImageOptions.Builder().showStubImage(R.drawable.downloadplaceholder).cacheInMemory().cacheOnDisc().showImageOnFail(R.drawable.loading).build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()).
defaultDisplayImageOptions(displayimageOptions).memoryCache(new WeakMemoryCache()).discCache(new UnlimitedDiscCache(cacheDir)).build();
if (ImageLoader.getInstance().isInited()) {
ImageLoader.getInstance().destroy();
}
ImageLoader.getInstance().init(config);
imageLoadingListener = new ImageLoadingListener() {
@Override
public void onLoadingStarted(String s, View view) {
}
@Override
public void onLoadingFailed(String s, View view, FailReason failReason) {
ImageView imageView = (ImageView) view;
imageView.setImageResource(R.drawable.android);
Log.i("Failed to Load " + s, failReason.toString());
}
@Override
public void onLoadingComplete(String s, View view, Bitmap bitmap) {
}
@Override
public void onLoadingCancelled(String s, View view) {
}
};
//Imageloader usage
ImageView imageView = new ImageView(getApplicationContext());
if (orientation == 1) {
imageView.setLayoutParams(new LinearLayout.LayoutParams(width / 6, width / 6));
} else {
imageView.setLayoutParams(new LinearLayout.LayoutParams(height / 6, height / 6));
}
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageLoader.displayImage(SERVER_HOSTNAME + "demos" + demo.getPathRoot() + demo.getRootName() + ".png", imageView, imageLoadingListener);
Esto puede cargar las imágenes de forma perezosa, ajustarlas correctamente al tamaño de la imagen que muestra una imagen de marcador de posición mientras se carga y mostrar un ícono predeterminado si la carga falla y el almacenamiento en caché de los recursos.
- También debería agregar que esta configuración actual mantiene la relación de aspecto de la imagen, por lo tanto, aplicable a su pregunta original
Sin usar ninguna clase o biblioteca personalizada:
<ImageView
android:id="@id/img"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter" />
scaleType="fitCenter"
(predeterminado cuando se omite)
- lo hará tan ancho como lo permita el padre y subir / bajar de escala según sea necesario manteniendo la relación de aspecto.
scaleType="centerInside"
- si el ancho intrínseco de
src
es más pequeño que el ancho del padre
centrará la imagen horizontalmente - si el ancho intrínseco de
src
es mayor que el ancho del padre
lo hará tan ancho como lo permita el padre y la relación de aspecto de mantenimiento a escala inferior.
No importa si usa los métodos android:src
o ImageView.setImage*
y la clave probablemente sea adjustViewBounds
.
Solo usa UniversalImageLoader y establece
DisplayImageOptions.Builder()
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
.build();
y sin ajustes de escala en ImageView
Tuve un problema similar una vez. Lo resolví haciendo un ImageView personalizado.
public class CustomImageView extends ImageView
A continuación, anule el método onMeasure de la vista de la imagen. Hice algo como esto, creo:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
Drawable drawable = getDrawable();
if (drawable == null) {
setMeasuredDimension(0, 0);
} else {
float imageSideRatio = (float)drawable.getIntrinsicWidth() / (float)drawable.getIntrinsicHeight();
float viewSideRatio = (float)MeasureSpec.getSize(widthMeasureSpec) / (float)MeasureSpec.getSize(heightMeasureSpec);
if (imageSideRatio >= viewSideRatio) {
// Image is wider than the display (ratio)
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int)(width / imageSideRatio);
setMeasuredDimension(width, height);
} else {
// Image is taller than the display (ratio)
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = (int)(height * imageSideRatio);
setMeasuredDimension(width, height);
}
}
} catch (Exception e) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Esto estirará la imagen para que se ajuste a la pantalla mientras mantiene la relación de aspecto.
Usa picasso que es fácil de usar.
En tu adaptador ...
@Override
public void getView(int position, View convertView, ViewGroup parent) {
ImageView view = (ImageView) convertView.findViewById(R.id.ranking_prod_pic);
Picasso.with(context).load(url).into(view); //url is image url
//you can resize image if you want
/* Picasso.with(context) .load(url) .resize(50, 50) .centerCrop() .into(view) */
}
Use android:scaleType="centerCrop"
.
Utilice estas propiedades en ImageView para mantener la relación de aspecto:
android:adjustViewBounds="true"
android:scaleType="fitXY"
Yo no necesito ningún código de Java. Sólo tienes que :
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
La clave está en el padre del partido para el ancho y la altura
intente con esta línea simple ... agregue esta línea en su código xml en la etiqueta de vista de imagen sin agregar ninguna dependencia android: scaleType = "fitXY"