web-dev-qa-db-fra.com

Mettre à l'échelle l'image pour remplir la largeur de l'image et conserver les proportions

J'ai un GridView. Les données de GridView sont demandées 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, récupère l'URL de l'image et charge l'image sur 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 la méthode 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 remplit la largeur ImageView, mais la hauteur ImageView ne se met pas à l'échelle. ImageView ne montre pas l'image entière.

Comment résoudre ce problème?

175
Joe

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

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

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

  • le rendra aussi large que le permet le parent et à la hausse ou à la baisse au besoin en conservant les proportions.

scaleType="centerInside"

  • si la largeur intrinsèque de src est inférieure à la largeur du parent
    va centrer l'image horizontalement
  • si la largeur intrinsèque de src est supérieure à la largeur du parent
    le rendra aussi large que le permet le parent et en conservant les proportions.

Peu importe si vous utilisez les méthodes Android:src ou ImageView.setImage* et que la clé est probablement la adjustViewBounds.

471
TWiStErRob

J'aime la réponse de arnefm mais il a commis 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 correctement dimensionné et n'aura aucun problème de dimension si (par exemple) est placé à l'intérieur de ScrollView

42
Alex Semeniuk

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

public class CustomImageView extends ImageView

Puis remplacez la méthode onMeasure de la vue image. 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 étendra l'image pour l'adapter à l'écran tout en conservant le rapport hauteur/largeur.

36
arnefm

Utilisez Android:scaleType="centerCrop".

20
Mark Buikema

J'ai fait quelque chose de similaire à ce qui précède, puis ma tête contre le mur pendant quelques heures parce que cela ne fonctionnait pas à l'intérieur d'un RelativeLayout. J'ai fini avec le code suivant:

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

Et puis pour empêcher RelativeLayout d'ignorer la dimension mesurée, j'ai fait ceci:

    <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>
9
Dave Cole

Cela ne s'appliquera pas si vous définissez l'image comme image d'arrière-plan dans ImageView, vous devez la définir à src (Android: src).

Merci.

5
Guna Sekhar

Essayez ceci: cela a résolu le problème pour moi

   Android:adjustViewBounds="true"
    Android:scaleType="fitXY"
5
Engineering Mind

Vous n'avez besoin d'aucun code Java. Vous devez juste:

<ImageView
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:adjustViewBounds="true"
    Android:scaleType="centerCrop" />

La clé est dans le parent du match pour la largeur et la hauteur

4
Romu Dizzy

Utilisez ces propriétés dans ImageView pour conserver les proportions:

Android:adjustViewBounds="true"
Android:scaleType="fitXY"
4
Atif Mahmood

essayez avec cette simple ligne ... ajoutez cette ligne dans votre code xml dans la balise de vue d'image sans ajouter de dépendance Android: scaleType = "fitXY"

2
ziddi609

utiliser Android: ScaleType = "fitXY" dans ImageView xml

2
Naveed Naeem

Vous pouvez essayer de faire ce que vous faites en chargeant manuellement les images, mais je vous recommande vivement de jeter un œil à niversal Image Loader .

Je l'ai récemment intégré à mon projet et je dois dire que c'est fantastique. Fait tout le souci de rendre les choses asynchrones, redimensionnement, mise en cache des images pour vous. C'est vraiment facile à intégrer et à mettre en place. En 5 minutes, vous pouvez probablement le faire faire ce que vous voulez.

Exemple de code:

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

Cela peut entraîner un chargement paresseux des images, les ajuster correctement à la taille de l'image. Afficher une image fictive lors du chargement et une icône par défaut en cas d'échec du chargement et de la mise en cache des ressources.

- Je devrais également ajouter que cette configuration actuelle conserve le format d'image, donc applicable à votre question d'origine

1
o0rebelious0o

Pour créer une image dont la largeur est égale à la largeur de l'écran et dont la hauteur est définie proportionnellement en fonction du rapport de format, procédez comme suit.

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

J'espère que cela t'aides.

1
Fathima km

Il suffit d'utiliser UniversalImageLoader et de définir

DisplayImageOptions.Builder()
    .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
    .build();

et pas de paramètres d'échelle sur ImageView

0
Artem

Utilisez picasso qui est facile à utiliser ..

Dans votre adaptateur ..

@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) */

}

http://square.github.io/picasso/ enter image description here

0
chiragkyada