Ridimensiona immagine per riempire la larghezza di ImageView e mantenere le proporzioni


200

Ho un GridView. I dati di GridViewsono richiesti da un server.

Ecco il layout dell'articolo in 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>

Richiedo i dati dal server, ottengo l'URL dell'immagine e carica l'immagine 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;
    }
}

e c'è il codice del getView(int position, View convertView, ViewGroup parent)metodo nell'adattatore

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

La dimensione dell'immagine è 210*210. Eseguo la mia applicazione sul mio Nexus 4. L'immagine riempie la ImageViewlarghezza, ma l' ImageViewaltezza non si ridimensiona. ImageViewnon mostra l'intera immagine.

Come posso risolvere questo problema?

Risposte:


549

Senza utilizzare classi o librerie personalizzate:

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

scaleType="fitCenter" (predefinito quando omesso)

  • lo renderà largo quanto il genitore consente e su / giù per la scala in base alle esigenze mantenendo le proporzioni.

scaleType="centerInside"

  • se la larghezza intrinseca di srcè inferiore alla larghezza principale centrerà
    l'immagine in senso orizzontale
  • se la larghezza intrinseca di srcè maggiore della larghezza principale
    , la renderà ampia quanto il padre consente e ridimensiona mantenendo le proporzioni.

Non importa se usi metodi android:srco ImageView.setImage*e probabilmente la chiave è adjustViewBounds.


5
android: layout_height = "wrap_content" android: adjustViewBounds = "true" android: scaleType = "fitCenter" fa il trucco
James Tan

@JamesTan fill_parentper larghezza è solo una buona pratica, funziona anche una dimensione fissa.
TWiStErRob,

@TWiStErRob mi rendo conto che ha bisogno di Android: adjustViewBounds = "true" con esso, altrimenti non si adatta di conseguenza per l'altezza. e sì, la larghezza adatta al genitore è la versione completa
James Tan,

9
Funziona come un fascino su API 19+, ma non su API 16 (testato). La vista personalizzata di Alex Semeniuk funziona anche su API 16.
Ashkan Sarlak,

1
@ F.Mysir frusta yes, sì, non importa quale sia il problema, ma per diffondere le buone pratiche, sono totalmente d'accordo.
TWiStErRob

42

Mi piace la risposta di arnefm ma ha fatto un piccolo errore (vedi commenti) che cercherò di correggere:

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

}

Quindi il tuo ImageViewverrà ridimensionato correttamente e non avrà problemi di dimensione se (ad esempio) viene inserito all'interno diScrollView


grazie, ho trovato la soluzione, proprio sotto la risposta di arnefm, il primo commento che ho aggiunto. questo thereè un link
Joe

36

Ho avuto un problema simile una volta. L'ho risolto creando un ImageView personalizzato.

public class CustomImageView extends ImageView

Quindi sovrascrivere il metodo onMeasure della visualizzazione immagine. Ho fatto qualcosa del genere credo:

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

Ciò allungherà l'immagine per adattarla allo schermo mantenendo le proporzioni.


1
vedi . la prima risposta
Joe

Bene, questa risposta non è precisa. Considera la situazione in cui hai impostato android:layout_height="wrap_content". In questo caso MeasureSpec.getSize(heightMeasureSpec)lo sarà 0e il tuo viewSideRatiorisultato Infinity(non c'è da stupirsi, il float Java consente tali valori). In questo caso sia tuo heightche widthlo sarà 0.
Alex Semeniuk,

1
Per fare in modo che il riempimento funzioni, ho dovuto scambiare (imageSideRatio> = viewSideRatio) in (imageSideRatio <viewSideRatio) .. altrimenti una buona risposta
Marek Halmo

23

Usa android:scaleType="centerCrop".


Non esattamente quale fosse la domanda, ma esattamente ciò di cui avevo bisogno!
Nickjm,

Puoi elaborare @Jameson? Intendi le versioni di Android?
Mick,

Se uso centerCrop, l'immagine viene leggermente tagliata in alto e in basso.
Sreekanth Karumanaghat,

9

Ho fatto qualcosa di simile a quanto sopra e poi ho sbattuto la testa contro il muro per alcune ore perché non funzionava all'interno di un RelativeLayout. Ho finito con il seguente codice:

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

E poi per evitare RelativeLayoutdi ignorare la dimensione misurata ho fatto questo:

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

5

Utilizzare queste proprietà in ImageView per mantenere le proporzioni:

android:adjustViewBounds="true"
android:scaleType="fitXY"

9
fitXY NON mantiene le proporzioni. Allunga l'immagine per adattarla esattamente alla larghezza e all'altezza del layout.
Carrello abbandonato

5

Questo non sarà applicabile se si imposta l'immagine come sfondo in ImageView, è necessario impostare su src (android: src).

Grazie.


5

Per creare un'immagine con larghezza uguale a larghezza dello schermo e altezza impostata proporzionalmente in base alle proporzioni, procedere come segue.

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

Spero che questo ti aiuti.


questa è la risposta migliore che ho trovato, sto cercando 2 giorni, grazie fathima
Karthick Ramanathan,

4

Prova questo: mi ha risolto il problema

   android:adjustViewBounds="true"
    android:scaleType="fitXY"

4

Non hai bisogno di alcun codice Java. Devi solo:

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

La chiave è nel genitore della corrispondenza per larghezza e altezza


centerCrop taglia effettivamente una parte dell'immagine.
Sreekanth Karumanaghat,

2

prova con questa semplice riga ... aggiungi questa riga nel tuo codice xml nel tag di visualizzazione delle immagini senza aggiungere alcuna dipendenza android: scaleType = "fitXY"


fitXY non mantiene le proporzioni, quindi l'immagine sarà probabilmente allungata
ProjectDelta

2

usa android: ScaleType = "fitXY" in ImageView xml


fitXY non mantiene le proporzioni, quindi l'immagine sarà probabilmente allungata
ProjectDelta

1

Puoi provare a fare quello che stai facendo caricando manualmente le immagini, ma ti consiglio vivamente di dare un'occhiata a Universal Image Loader .

Di recente l'ho integrato nel mio progetto e devo dire che è fantastico. Fa tutto il preoccuparsi di rendere le cose asincrone, ridimensionare, memorizzare nella cache le immagini per te. È davvero facile da integrare e configurare. Entro 5 minuti puoi probabilmente farlo facendo quello che vuoi.

Codice di esempio:

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

Questo può caricare le immagini in modo pigro, adattarle correttamente alla dimensione dell'immagine Visualizza che mostra un'immagine segnaposto durante il caricamento e mostra un'icona predefinita se il caricamento non riesce e memorizza nella cache le risorse.

- Vorrei anche aggiungere che questa configurazione attuale mantiene le proporzioni dell'immagine, quindi applicabili alla domanda originale


0

Basta usare UniversalImageLoader e impostare

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

e nessuna impostazione di scala su ImageView


0

Ho avuto un problema simile, ho trovato il motivo per questo è perché è necessario calcolare il dp. Android Studio sta calcolando il ImageViewquando lo si carica dalla drawable, ma quando si utilizza un altro metodo, come il caricamento dal bitmap della dpnon viene contabilizzata automaticamente,

Ecco il mio XML

<ImageView
  android:id="@+id/imageViewer"
  android:layout_width="match_parent"
  android:layout_height="match_parent"//dp is not automaticly updated, when loading from a other source
  android:scaleType="fitCenter"
  tools:srcCompat="@drawable/a8" />

Sto usando Kotlin e sto caricando un disegno da un file di risorse, ecco come lo calcolo

val d = Drawable.createFromStream(assets.open("imageData/${imageName}.png"), null)
bitHeight = d.minimumHeight//get the image height
imageViewer.layoutParams.height = (bitHeight * resources.displayMetrics.density).toInt()//set the height
imageViewer.setImageDrawable(d)//set the image from the drawable
imageViewer.requestLayout()//here I apply it to the layout

-1

Usa picasso che è facile da usare ..

Nel tuo adattatore ..

@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/ inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.