Android: comment étirer une image sur la largeur de l'écran tout en maintenant le format d'image?

je veux télécharger une image (de taille inconnue, mais qui est toujours à peu près carrée) et l'afficher de sorte qu'elle remplisse l'écran horizontalement, et s'étire verticalement pour maintenir le rapport d'aspect de l'image, sur n'importe quelle taille d'écran. Voici ma (non-travail) du code. Il étire l'image horizontalement, mais pas verticalement, de sorte qu'elle est écrasée...

ImageView mainImageView = new ImageView(context);
    mainImageView.setImageBitmap(mainImage); //downloaded from server
    mainImageView.setScaleType(ScaleType.FIT_XY);
    //mainImageView.setAdjustViewBounds(true); 
    //with this line enabled, just scales image down
    addView(mainImageView,new LinearLayout.LayoutParams( 
            LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
118
demandé sur fredley 2010-06-07 20:05:53

17 réponses

j'ai accompli ceci avec une vue personnalisée. Définissez layout_width= "fill_parent" et layout_height=" wrap_content", et pointez-le vers le drawable approprié:

public class Banner extends View {

  private final Drawable logo;

  public Banner(Context context) {
    super(context);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  public Banner(Context context, AttributeSet attrs) {
    super(context, attrs);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  public Banner(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  @Override protected void onMeasure(int widthMeasureSpec,
      int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = width * logo.getIntrinsicHeight() / logo.getIntrinsicWidth();
    setMeasuredDimension(width, height);
  }
}
132
répondu Bob Lee 2010-06-08 13:38:37

à la fin, j'ai généré les dimensions manuellement, ce qui fonctionne très bien:

DisplayMetrics dm = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = width * mainImage.getHeight() / mainImage.getWidth(); //mainImage is the Bitmap I'm drawing
addView(mainImageView,new LinearLayout.LayoutParams( 
        width, height));
24
répondu fredley 2010-06-08 17:28:33

je viens de lire le code source pour ImageView et il est fondamentalement impossible sans utiliser les solutions de sous-classement dans ce fil. Dans 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 rembourrage.

et ensuite:

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 placé 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 agrandies . Je considère que C'est un bug, mais bonne chance pour que Google s'en aperçoive ou le Répare. Edit: mangeant mes propres mots, j'ai soumis un rapport de bogue et ils disent qu'il a été corrigé dans une future version!

une autre solution

Voici une autre solution subclassée, mais vous devrait (en théorie, Je ne l'ai pas vraiment testé beaucoup!) être en mesure de l'utiliser partout où vous ImageView . Pour l'utiliser, Mettez 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);
        }
    }
}
21
répondu Timmmm 2012-10-02 10:56:36

mettre adjustViewBounds à true et en utilisant un groupe de vue linéaire a très bien fonctionné pour moi. Pas besoin de sous-classe ou de demander des paramètres de périphérique:

//NOTE: "this" is a subclass of LinearLayout
ImageView splashImageView = new ImageView(context);
splashImageView.setImageResource(R.drawable.splash);
splashImageView.setAdjustViewBounds(true);
addView(splashImageView);
17
répondu Matt Stoker 2011-04-15 23:49:05

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 souligner que vous pouvez obtenir une solution généralisable à partir de ce que Bob Lee a fait en étendant la vue et en dépassant onMeasure. De cette façon, vous pouvez l'utiliser avec n'importe quel dessin que vous voulez, et il ne se brisera pas s'il n'y a pas d'image:

    public class CardImageView extends View {
        public CardImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

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

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

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            Drawable bg = getBackground();
            if (bg != null) {
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = width * bg.getIntrinsicHeight() / bg.getIntrinsicWidth();
                setMeasuredDimension(width,height);
            }
            else {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    }
13
répondu duhrer 2012-04-07 10:10:40

dans certains cas, cette formule magique résout magnifiquement le problème.

pour toute personne aux prises avec ce qui vient d'une autre plate-forme, l'option " taille et la forme pour s'adapter " est géré magnifiquement dans Android, mais il est difficile de trouver.

vous voulez typiquement cette combinaison:

  • largeur match parent,
  • hauteur du contenu de l'enveloppe,
  • adjustViewBounds activée (sic)
  • scale fitCenter
  • cropToPadding OFF (sic)

Alors c'est automatique et incroyable.

si vous êtes un dev iOS, il est tout simplement incroyable comment vous pouvez faire "hauteurs de cellules totalement dynamique" dans une vue de table .. euh, je veux dire ListView. Profiter.

<com.parse.ParseImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/post_image"
    android:src="@drawable/icon_192"
    android:layout_margin="0dp"
    android:cropToPadding="false"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter"
    android:background="#eff2eb"/>

enter image description here

10
répondu Fattie 2014-11-12 18:18:22

Je l'ai fait avec ces valeurs dans une distribution linéaire:

Scale type: fitStart
Layout gravity: fill_horizontal
Layout height: wrap_content
Layout weight: 1
Layout width: fill_parent
5
répondu helduel 2011-11-09 20:39:44

j'ai réussi à réaliser ceci en utilisant ce code XML seulement. Il se peut que eclipse ne rende pas la hauteur pour montrer qu'elle s'étend pour s'adapter; cependant, quand vous exécutez réellement ceci sur un périphérique, Il rend correctement et fournit le résultat désiré. (du moins pour moi)

<FrameLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content">

     <ImageView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:adjustViewBounds="true"
          android:scaleType="centerCrop"
          android:src="@drawable/whatever" />
</FrameLayout>
5
répondu NeilDA 2014-04-09 20:23:37

tout le monde fait ce programme donc j'ai pensé que cette réponse conviendrait parfaitement ici. Ce code a fonctionné pour moi dans le xml. Je ne pense pas encore à ratio, mais toujours voulu placer cette réponse si elle aiderait quelqu'un.

android:adjustViewBounds="true"

santé..

5
répondu Sindri Þór 2015-09-20 17:20:58

une solution très simple est d'utiliser simplement les caractéristiques fournies par RelativeLayout .

voici le xml qui le rend possible avec Android standard Views :

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
        <LinearLayout
            android:id="@+id/button_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_alignParentBottom="true"
            >
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </LinearLayout>
        <ImageView 
            android:src="@drawable/cat"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:scaleType="centerCrop"
            android:layout_above="@id/button_container"/>
    </RelativeLayout>
</ScrollView>

le truc est que vous mettez le ImageView pour remplir l'écran mais il doit être au-dessus des autres layouts. De cette façon, vous réalisez tout ce dont vous avez besoin.

3
répondu Warpzit 2013-09-30 07:17:21

sa simple question de définir adjustViewBounds="true" et scaleType="fitCenter" dans le fichier XML pour ImageView!

<ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/image"

        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        />

Note: layout_width est réglé sur match_parent

2
répondu Kaushik NP 2017-02-26 09:35:31

vous définissez ScaleType à ScaleType.FIT_XY. Selon le javadocs , cela permettra d'étirer l'image pour s'adapter à toute la zone, en changeant le rapport d'aspect si nécessaire. Cela expliquerait le comportement que vous voyez.

Pour obtenir le comportement que vous voulez... FIT_CENTER, FIT_START, ou FIT_END sont proches, mais si l'image est plus étroite que haute, elle ne commencera pas à remplir la largeur. Vous pouvez regarder comment ils sont mis en œuvre cependant, et vous devriez probablement être en mesure de comprendre comment l'ajuster en fonction de votre but.

1
répondu Cheryl Simon 2010-06-07 17:48:31

ScaleType.CENTER_CROP fera ce que vous voulez: étirez jusqu'à la pleine largeur, et dimensionnez la hauteur en conséquence. si à l'échelle de la hauteur dépasse les limites de l'écran, l'image sera rognée.

1
répondu P.Melch 2011-02-14 22:32:46

regardez il y a une solution beaucoup plus facile à votre problème:

ImageView imageView;

protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_layout);
    imageView =(ImageView)findViewById(R.id.your_imageView);
    Bitmap imageBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.your_image);
    Point screenSize = new Point();
    getWindowManager().getDefaultDisplay().getSize(screenSize);
    Bitmap temp = Bitmap.createBitmap(screenSize.x, screenSize.x, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(temp);
    canvas.drawBitmap(imageBitmap,null, new Rect(0,0,screenSize.x,screenSize.x), null);
    imageView.setImageBitmap(temp);
}
1
répondu user3673209 2015-06-09 20:46:37

vous pouvez utiliser mon StretchableImageView préserver le rapport d'aspect (par la largeur ou par la hauteur) en fonction de la largeur et la hauteur de tirable:

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

public class StretchableImageView extends ImageView{

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

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if(getDrawable()!=null){
            if(getDrawable().getIntrinsicWidth()>=getDrawable().getIntrinsicHeight()){
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = width * getDrawable().getIntrinsicHeight()
                            / getDrawable().getIntrinsicWidth();
                setMeasuredDimension(width, height);
            }else{
                int height = MeasureSpec.getSize(heightMeasureSpec);
                int width = height * getDrawable().getIntrinsicWidth()
                            / getDrawable().getIntrinsicHeight();
                setMeasuredDimension(width, height);
            }
        }
    }
}
1
répondu anivaler 2015-11-12 06:55:41

pour moi l'android:scaleType="centerCrop" n'a pas résolu mon problème. Il a en fait élargi l'image beaucoup plus. J'ai donc essayé avec android: scaleType= "fitXY" et il a fonctionné excellent.

0
répondu Ricardo 2014-03-13 20:05:59

Ce travail bien que par mon exigence

<ImageView android:id="@+id/imgIssue" android:layout_width="fill_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:scaleType="fitXY"/>

0
répondu Anand Savjani 2015-08-24 06:00:29