238 votes

Mettre l'image à l'échelle pour remplir la largeur de l'ImageView et conserver le rapport d'aspect

J'ai un GridView . Les données de GridView est demandé par un serveur.

Voici la disposition des éléments dans 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>

Je demande des données au serveur, je récupère l'URL de l'image et je charge l'image sur le serveur. 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;
    }
}

et il y a le code de getView(int position, View convertView, ViewGroup parent) dans l'adaptateur

Bitmap bitmap = BitmapUtil.loadBitmapFromHttpUrl(product.getHttpUrl());
prodImg.setImageBitmap(bitmap);

La taille de l'image est 210*210 . J'exécute mon application sur mon Nexus 4. L'image se remplit ImageView largeur, mais le ImageView La hauteur n'est pas mise à l'échelle. ImageView ne montre pas l'image entière.

Comment puis-je résoudre ce problème ?

635voto

TWiStErRob Points 1233

Sans utiliser de classes ou de bibliothèques personnalisées :

<ImageView
    android:id="@id/img"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter" />

scaleType="fitCenter" (par défaut si omis)

  • le rendra aussi large que le parent le permet et l'augmentera ou le diminuera selon les besoins en respectant les proportions.

scaleType="centerInside"

  • si la largeur intrinsèque de src est plus petite que la largeur du parent
    centre l'image horizontalement
  • si la largeur intrinsèque de src est plus grande que la largeur du parent
    le rendra aussi large que le parent le permet et le réduira en gardant le ratio d'aspect.

Peu importe si vous utilisez android:src o ImageView.setImage* et la clé est probablement la adjustViewBounds .

43voto

Alex Semeniuk Points 519

J'aime la réponse d'arnefm mais il a fait une petite erreur (voir commentaires) que je vais essayer de corriger :

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);
    }
  }

}

Ainsi, votre ImageView sera mis à l'échelle correctement et n'aura aucun problème de dimension si (par exemple) il est placé à l'intérieur de ScrollView

40voto

arnefm Points 938

J'ai eu un problème similaire une fois. Je l'ai résolu en créant une ImageView personnalisée.

public class CustomImageView extends ImageView

Remplacez ensuite la méthode onMeasure de l'imageview. J'ai fait quelque chose comme ça, je crois :

    @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);
    }

Cela permet d'étirer l'image pour l'adapter à l'écran tout en conservant le rapport hauteur/largeur.

29voto

Mark Buikema Points 1098

Utilisez android:scaleType="centerCrop" .

10voto

Vijay Points 464

POUR LA VUE DES IMAGES (définir ces paramètres)

android:layout_width     = "match_parent"
android:layout_height    = "wrap_content"
android:scaleType        = "fitCenter"
android:adjustViewBounds = "true"

Maintenant, quelle que soit la taille de l'image, sa largeur correspondra à celle du parent et sa hauteur sera adaptée au ratio. J'ai testé cela et je suis sûr à 100%.

nous voulons ceci adjustViewBound = true

pas ça adjustViewBound = false

// Results will be: 
Image width -> stretched as match parent
Image height -> according to image width (maximum to aspect ratio)

// like the first one

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X