77 votes

Android ImageView permet de mettre à l'échelle une image plus petite sur la largeur avec une hauteur flexible sans recadrage ni distorsion.

Souvent posée, cette question n'a jamais reçu de réponse (du moins pas de manière reproductible).

J'ai une vue d'image avec une image qui est plus petit que la vue. Je souhaite mettre l'image à l'échelle de la largeur de l'écran et ajuster la hauteur de l'ImageView pour refléter la hauteur proportionnelle de l'image.

<ImageView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
/>

L'image est centrée à sa taille d'origine (plus petite que la largeur de l'écran) avec des marges sur les côtés. Ce n'est pas bon.

J'ai donc ajouté

android:adjustViewBounds="true" 

Même effet, rien de bon. J'ai ajouté

android:scaleType="centerInside"

Même effet, rien de bon. J'ai changé centerInside a fitCenter . Même effet, rien de bon. J'ai changé centerInside a centerCrop .

android:scaleType="centerCrop"

Enfin, l'image est échelonné à la largeur de l'écran - mais décolletée en haut et en bas ! J'ai donc modifié centerCrop a fitXY .

android:scaleType="fitXY"

L'image est maintenant adaptée à la largeur de l'écran mais no échelonné sur l'axe des y, ce qui donne une valeur de déformé image.

Suppression android:adjustViewBounds="true" n'a pas d'effet. L'ajout d'un android:layout_gravity comme suggéré ailleurs, n'a encore une fois aucun effet.

J'ai essayé d'autres combinaisons, sans succès. Alors, s'il vous plaît, quelqu'un sait-il :

Comment configurer le XML d'un ImageView pour qu'il remplisse la largeur de l'écran, qu'il mette à l'échelle une image plus petite pour qu'elle remplisse la totalité de l'écran et qu'il affiche l'image avec son rapport d'aspect sans distorsion ni recadrage ?

EDIT : J'ai également essayé de définir une hauteur numérique arbitraire. Cela n'a d'effet qu'avec l'option centerCrop de l'environnement. L'image est déformée verticalement en fonction de la hauteur de vue.

110voto

Mark Martinsson Points 401

J'ai résolu ce problème en créant une classe Java que vous incluez dans votre fichier de présentation :

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

Vous pouvez maintenant utiliser cette méthode en ajoutant votre classe à votre fichier de mise en page :

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

21voto

Mundi Points 33074

Il n'existe pas de solution viable dans le cadre de la norme de présentation XML.

La seule manière fiable de réagir à une taille d'image dynamique est d'utiliser la fonction LayoutParams en code.

Décevant.

8voto

Budius Points 12015
  android:scaleType="fitCenter"

Calculer une échelle qui maintiendra le rapport d'aspect original de src, mais qui garantira également que src s'insère entièrement dans dst. Au moins un axe (X ou Y) s'ajustera exactement. Le résultat est centré à l'intérieur de dst.

éditer :

Le problème est que le layout_height="wrap_content" ne permet pas à l'image de se développer. Vous devrez définir une taille pour cette modification.

  android:layout_height="wrap_content"

à

  android:layout_height="100dp"  // or whatever size you want it to be

éditer2 :

fonctionne bien :

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:scaleType="fitCenter"
    android:src="@drawable/img715945m" />

8voto

Il s'agit d'un petit complément à l'excellente solution de Mark Martinsson.

Si la largeur de votre image est supérieure à sa hauteur, la solution de Mark laissera de l'espace en haut et en bas de l'écran.

La méthode ci-dessous corrige ce problème en comparant d'abord la largeur et la hauteur : si la largeur de l'image est supérieure à la hauteur, la hauteur sera adaptée à la hauteur de l'écran, puis la largeur sera adaptée afin de préserver le rapport hauteur/largeur. De même, si la hauteur de l'image est supérieure à la largeur, la largeur sera adaptée à la largeur de l'écran, puis la hauteur sera adaptée pour préserver le rapport hauteur/largeur.

En d'autres termes, il répond correctement à la définition de scaleType="centerCrop" :

http://developer.Android.com/reference/Android/widget/ImageView.ScaleType.html

Mettre l'image à l'échelle de manière uniforme (conserver l'aspect de l'image). les deux dimensions (largeur et hauteur) de l'image sera égal ou plus grand que la dimension correspondante de la vue (moins le remplissage).

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

Cette solution fonctionne automatiquement en mode portrait ou paysage. Vous y faites référence dans votre mise en page comme vous le faites dans la solution de Mark. Par exemple :

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

3voto

tbm Points 177

J'ai rencontré le même problème, mais avec une hauteur fixe, une largeur mise à l'échelle en conservant le rapport d'aspect original de l'image. J'ai résolu le problème par une mise en page linéaire pondérée. J'espère que vous pourrez la modifier en fonction de vos besoins.

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

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