118 votes

Android : Comment étirer une image à la largeur de l’écran tout en conservant les proportions ?

Je veux télécharger une image (de taille inconnue, mais qui est toujours à peu près carré) et affichez-la afin qu’elle remplisse l’écran horizontalement et s’étend verticalement pour conserver les proportions de l’image, sur n’importe quelle taille de l’écran. Voici mon code (inactifs). Il étire l’image horizontalement, mais pas verticalement, donc il est écrasé...

133voto

Bob Lee Points 1294

J’ai accompli ceci avec un affichage personnalisé. Définissez layout_width = « fill_parent » et layout_height = « wrap_content » et le diriger à l’approprié drawable :

24voto

Tom Medley Points 9722

Finalement, j’ai généré les dimensions manuellement, qui fonctionne très bien :

21voto

Timmmm Points 9909

Je viens de lire le code source pour ImageView et il est pratiquement impossible sans l'aide de la sous-classement des solutions dans ce thread. En ImageView.onMeasure nous arrivons à ces lignes:

        // Get the max possible width given our constraints
        widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);

        // Get the max possible height given our constraints
        heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);

h et w sont les dimensions de l'image, et p* est le remplissage.

Et puis:

private int resolveAdjustedSize(int desiredSize, int maxSize,
                               int measureSpec) {
    ...
    switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            /* Parent says we can be as big as we want. Just don't be larger
               than max size imposed on ourselves.
            */
            result = Math.min(desiredSize, maxSize);

Donc, si vous avez un layout_height="wrap_content" il sera mis en widthSize = w + pleft + pright, ou en d'autres termes, la largeur maximale est égale à la largeur de l'image.

Cela signifie que , sauf si vous définissez une taille exacte, les images ne sont JAMAIS élargie. Je considère que cela est un bug, mais bonne chance pour Google de prendre l'avis ou le fixer. Edit: Manger mes propres mots, j'ai soumis un rapport de bug et ils disent qu'il a été corrigé dans une future version!

Une autre solution

Voici un autre sous-classé solution de contournement, mais vous devrait (en théorie, je n'ai pas vraiment testé beaucoup!) être en mesure de l'utiliser partout où vous ImageView. Pour l'utiliser ensemble layout_width="match_parent", et layout_height="wrap_content". Il est beaucoup plus générale que la solution retenue. E. g. vous pouvez le faire adapter à la hauteur ainsi que l'ajustement à la largeur.

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;

// This works around the issue described here: http://stackoverflow.com/a/12675430/265521
public class StretchyImageView extends ImageView
{

    public StretchyImageView(Context context)
    {
        super(context);
    }

    public StretchyImageView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public StretchyImageView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // Call super() so that resolveUri() is called.
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // If there's no drawable we can just use the result from super.
        if (getDrawable() == null)
            return;

        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);

        int w = getDrawable().getIntrinsicWidth();
        int h = getDrawable().getIntrinsicHeight();
        if (w <= 0)
            w = 1;
        if (h <= 0)
            h = 1;

        // Desired aspect ratio of the view's contents (not including padding)
        float desiredAspect = (float) w / (float) h;

        // We are allowed to change the view's width
        boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;

        // We are allowed to change the view's height
        boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;

        int pleft = getPaddingLeft();
        int pright = getPaddingRight();
        int ptop = getPaddingTop();
        int pbottom = getPaddingBottom();

        // Get the sizes that ImageView decided on.
        int widthSize = getMeasuredWidth();
        int heightSize = getMeasuredHeight();

        if (resizeWidth && !resizeHeight)
        {
            // Resize the width to the height, maintaining aspect ratio.
            int newWidth = (int) (desiredAspect * (heightSize - ptop - pbottom)) + pleft + pright;
            setMeasuredDimension(newWidth, heightSize);
        }
        else if (resizeHeight && !resizeWidth)
        {
            int newHeight = (int) ((widthSize - pleft - pright) / desiredAspect) + ptop + pbottom;
            setMeasuredDimension(widthSize, newHeight);
        }
    }
}

17voto

Matt Stoker Points 230

AdjustViewBounds true et en utilisant un LinearLayout voir group a très bien fonctionné pour moi. Pas besoin de la sous-classe ou demander des mesures de l’appareil :

14voto

duhrer Points 101

J’ai été aux prises avec ce problème sous une forme ou une autre pendant des siècles, Merci, Merci, Merci...  :)

Je voulais juste faire remarquer que vous pouvez obtenir une solution généralisable de quel Bob Lee fait en juste qui s’étend de la vue et en substituant onMeasure. De cette façon vous pouvez l’utiliser avec n’importe quel élément graphique que vous voulez, et il ne cassera pas si il n’y a pas d’image :

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