2012-12-21 16 views
68

Spesso chiesto, non ha mai risposto (almeno non in modo riproducibile).Android ImageView ridimensiona l'immagine in larghezza con altezza flessibile senza ritaglio o distorsione

Ho una visualizzazione immagine con un'immagine che è più piccola rispetto alla visualizzazione. Voglio ridimensionare l'immagine alla larghezza dello schermo e regolare l'altezza di ImageView per riflettere l'altezza proporzionalmente corretta dell'immagine.

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

Ciò comporta l'immagine centrata nelle sue dimensioni originali (più piccolo della larghezza dello schermo) con margini laterali. Non buono.

così ho aggiunto

android:adjustViewBounds="true" 

Stesso effetto, non va bene. Ho aggiunto

android:scaleType="centerInside" 

Stesso effetto, non va bene. Ho cambiato centerInside a fitCenter. Lo stesso effetto, non va bene. Ho cambiato centerInside a centerCrop.

android:scaleType="centerCrop" 

Ora, finalmente, l'immagine è scalato alla larghezza dello schermo - ma ritagliata in alto e in basso! Così ho cambiato centerCrop in fitXY.

android:scaleType="fitXY" 

Ora l'immagine viene adattata alla larghezza dello schermo, ma non scalato sulla y, risultando in un Immagine distorta.

La rimozione di android:adjustViewBounds="true" non ha alcun effetto. L'aggiunta di un android:layout_gravity, come suggerito altrove, non ha di nuovo alcun effetto.

Ho provato altre combinazioni - inutilmente. Quindi, per favore qualcuno sa:

Come si imposta l'XML di un ImageView per riempire la larghezza dello schermo, ridimensionare un'immagine più piccola per riempire l'intera vista, visualizzando l'immagine con il suo rapporto aspetto senza distorsione o ritaglio?

MODIFICA: ho anche provato a impostare un'altezza numerica arbitraria. Questo ha effetto solo con l'impostazione centerCrop. Distorcerà l'immagine verticalmente in base all'altezza della vista.

+0

Hai provato 'Android: scaleType = "fitCenter"'? – MCeley

+0

@MCeley hai? (spoiler: non funziona.) – BrainSlugs83

+0

@ BrainSlugs83 Ho e funziona per me, ancora. Inoltre, è stata posta la domanda per determinare ciò che il richiedente aveva provato. Non è necessario per l'ansia, soprattutto non sette mesi dopo che è stato pubblicato. – MCeley

risposta

18

Non v'è alcun soluzione praticabile all'interno dello standard di layout XML.

L'unico modo affidabile per reagire a una dimensione di immagine dinamica è utilizzare LayoutParams nel codice.

Deludente.

7
android:scaleType="fitCenter" 

Calcolare una scala che manterrà le proporzioni src originali, ma assicurerà anche che src si adatti interamente al dst. Almeno un asse (X o Y) si adatterà esattamente. Il risultato è centrato all'interno di dst.

edit:

Il problema qui è che il layout_height="wrap_content" non è "che permette" l'immagine di espandersi.Dovrete impostare una dimensione per lui, per quel cambiamento

android:layout_height="wrap_content" 

a

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

EDIT2:

funziona bene:

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

Ciò risulta nella prima versione dell'immagine: centrata, non espansa orizzontalmente, con margini su entrambi i lati. Non buono. – Mundi

+0

modificato la mia risposta, check it out – Budius

+1

Questo non funziona. Ne risulta un'immagine con l'altezza esatta, ma non espansa orizzontalmente. Non buono. Vedi anche la mia modifica nella domanda. – Mundi

105

Ho risolto questo con la creazione di un java-classe che si include nel layout file:

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

Ora, si utilizza questo dal aggiunto la classe per il layout-file:

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

+1 Ottima soluzione, funziona perfettamente anche per Nexus 7. E la parte migliore è che funziona anche correttamente all'interno dell'Editor di layout in Eclipse. – Ridcully

+0

Funziona su Galaxy S4. Perché non dovrebbe :) THx – Malachiasz

+0

Grazie. Ottima soluzione. Abbastanza facile modificare per fare lo stesso sulla base di heightMeasureSpec. – speedynomads

3

Mi sono imbattuto nello stesso problema, ma con un'altezza fissa, larghezza ridimensionata mantenendo le proporzioni originali dell'immagine. L'ho risolto tramite un layout lineare ponderato. Spero che tu possa modificarlo per le tue esigenze.

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

Questa soluzione ha funzionato benissimo per me. Mi ha permesso di dare al mio ImageView un'altezza specifica e di fare in modo che ImageView regoli dinamicamente la larghezza per mantenere le proporzioni. – Luke

7

Questa è una piccola aggiunta all'ottima soluzione di Mark Martinsson.

Se la larghezza dell'immagine è maggiore della sua altezza, la soluzione di Mark lascerà spazio nella parte superiore e inferiore dello schermo.

Il seguente corregge questo confrontando prima la larghezza e l'altezza: se l'ampiezza dell'immagine> = altezza, quindi ridimensiona l'altezza in modo che corrisponda all'altezza dello schermo, quindi ridimensiona la larghezza per mantenere le proporzioni. Allo stesso modo, se l'altezza dell'immagine> larghezza, ridimensiona la larghezza in modo che corrisponda alla larghezza dello schermo e quindi ridimensiona l'altezza per mantenere le proporzioni.

In altre parole, esso soddisfa adeguatamente la definizione di scaleType="centerCrop":

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

scala dell'immagine uniformemente (mantenere proporzioni dell'immagine) in modo che entrambe le dimensioni (larghezza ed altezza) dell'immagine sarà uguale ao maggiore di la dimensione corrispondente della vista (meno riempimento).

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

Questa soluzione funziona automaticamente in modalità ritratto o paesaggio. Tu fai riferimento al tuo layout proprio come fai nella soluzione di Mark. Es .:

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

Ho avuto lo stesso problema, come il tuo. Dopo 30 minuti di provare diverse varianti ho risolto il problema in questo modo.Ti dà la altezza flessibili, e la larghezza regolato al genitore larghezza

<ImageView 
      android:id="@+id/imageview_company_logo" 
      android:layout_width="fill_parent" 
      android:layout_height="fill_parent" 
      android:adjustViewBounds="true" 
      android:scaleType="fitCenter" 
      android:src="@drawable/appicon" /> 
+0

La chiave qui è usare adjustViewBounds – user3690202

0

Un'altra aggiunta alla soluzione di Mark Matinsson. Ho scoperto che alcune delle mie immagini erano ridimensionate rispetto ad altre. Così ho modificato la classe in modo che l'immagine sia ridimensionata di un fattore massimo. Se l'immagine è troppo piccola per essere ridimensionata alla larghezza massima senza diventare sfocata, smette di ridimensionare oltre il limite massimo.

public class DynamicImageView extends ImageView { 

final int MAX_SCALE_FACTOR = 2; 
public DynamicImageView(final Context context) { 
    super(context); 
} 

@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 
     int width = View.MeasureSpec.getSize(widthMeasureSpec); 
     if (width > (d.getIntrinsicWidth()*MAX_SCALE_FACTOR)) width = d.getIntrinsicWidth()*MAX_SCALE_FACTOR; 
     final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight()/d.getIntrinsicWidth()); 
     this.setMeasuredDimension(width, height); 
    } else { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    } 
} 

}

0

versione Kotlin di Mark Martinsson answer:

class DynamicImageView(context: Context, attrs: AttributeSet) : AppCompatImageView(context, attrs) { 
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 
    val drawable = this.drawable 

    if (drawable != null) { 
     //Ceil not round - avoid thin vertical gaps along the left/right edges 
     val width = View.MeasureSpec.getSize(widthMeasureSpec) 
     val height = Math.ceil((width * drawable.intrinsicHeight.toFloat()/drawable.intrinsicWidth).toDouble()).toInt() 
     this.setMeasuredDimension(width, height) 
    } else { 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec) 
    } 
} 
Problemi correlati