Android: come allungare un'image alla width dello schermo pur mantenendo il rapporto di aspetto?

Voglio scaricare un'image (di size sconosciute, ma che è sempre approssimativamente quadrata) e visualizzarla in modo che riempia lo schermo in orizzontale e si estende verticalmente per mantenere il rapporto di aspetto dell'image, a qualsiasi dimensione dello schermo. Ecco il mio codice (non funzionante). Si allunga orizzontalmente l'image, ma non in verticale, quindi viene schiacciata …

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

  • Come build apk senza eclipse o Modificare l'edificio apk con un file di configuration?
  • Android Google Directions Service utilizzabile nativamente? con il canvasio avvolgitore? Sono disponibili routes di trasporto pubblico / bici?
  • Un cursore nelle colonne di riferimento di Android da 0 o 1?
  • È ansible eseguire i comandi adb tramite la mia applicazione Android?
  • Estrarre l'elenco dei contatti in formato vcf
  • Non si può aggiungere due volte la visualizzazione di mappe Android con i frammenti?
  • com.google.android.maps non esiste un errore strano
  • come get i dati dall'object Json?
  • Utilizzo di un database SQLite in Libgdx
  • Passare dal maestro AOSP a froyo
  • WebViewClient onReceivedError deprecata, la nuova versione non rileva tutti gli errori
  • Android SDK non riconosce il dispositivo debug-capable
  • 17 Solutions collect form web for “Android: come allungare un'image alla width dello schermo pur mantenendo il rapporto di aspetto?”

    Ho realizzato questo con una vista personalizzata. Impostare layout_width = "fill_parent" e layout_height = "wrap_content" e indicarlo al disegnatore appropriato:

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

    Alla fine ho generato manualmente le size, che funziona ottimamente:

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

    Ho appena letto il codice sorgente di ImageView ed è fondamentalmente imansible senza utilizzare le soluzioni di sottoclass in questo thread. In ImageView.onMeasure arriviamo a queste righe:

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

    Dove h e w sono le size dell'image, e p* è l'imbottitura.

    E poi:

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

    Quindi, se si dispone di un layout_height="wrap_content" imposterà widthSize = w + pleft + pright , ovvero la width massima è uguale alla width dell'image.

    Ciò significa che se non si imposta una dimensione esatta, le immagini non vengono mai ingrandite . Ritengo che questo sia un bug, ma buona fortuna che port Google a prendere nota o risolvere il problema. Modifica: Mangiare le mie parole, ho presentato un bug report e dicono che è stato fissato in una release futura!

    Un'altra soluzione

    Ecco un'altra soluzione alternativa sottoclass, ma devi (in teoria, non ho veramente provato molto!) Essere in grado di utilizzarlo ovunque tu ImageView . Per utilizzarlo impostare layout_width="match_parent" , e layout_height="wrap_content" . È anche molto più generale della soluzione accettata. Ad esempio, è ansible fare altezza e altezza.

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

    L'impostazione di adjustViewBounds su true e l'utilizzo di un gruppo di visualizzazione LinearLayout ha funzionato molto bene per me. Non è necessario sottostrarsi o chiedere metriche del dispositivo:

     //NOTE: "this" is a subclass of LinearLayout ImageView splashImageView = new ImageView(context); splashImageView.setImageResource(R.drawable.splash); splashImageView.setAdjustViewBounds(true); addView(splashImageView); 

    Ho combattuto con questo problema in una forma o nell'altro per AGES, grazie, grazie, GRAZIE …. 🙂

    Volevo solo sottolineare che è ansible get una soluzione generalizzabile da ciò che Bob Lee ha fatto solo estendendo la vista e superando onMeasure. In questo modo puoi utilizzare questo con qualsiasi traccia che vuoi, e non romperà se non c'è 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); } } } 

    In alcuni casi questa formula magica risolve splendidamente il problema.

    Per chiunque si lotta con questo proveniente da un'altra piattaforma, l'opzione "size e forma a misura" viene gestita in modo bello in Android, ma è difficile da trovare.

    In genere desideri questa combinazione:

    • parente di corrispondenza di width,
    • contenuto dell'involucro di altezza,
    • adjustViewBounds triggersto (sic)
    • scala fitCenter
    • cropToPadding OFF (sic)

    Allora è automatico e sorprendente.

    Se sei un iOS dev, è assolutamente incredibile come puoi semplicemente "altezze cellulari completamente dinamiche" in una vista tabella .. err, intendo ListView. Godere.

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

    immettere qui la descrizione dell'immagine

    Lo ho fatto con questi valori all'interno di un LinearLayout:

     Scale type: fitStart Layout gravity: fill_horizontal Layout height: wrap_content Layout weight: 1 Layout width: fill_parent 

    Sono riuscito a raggiungere questo objective solo utilizzando questo codice XML. Potrebbe essere il caso che l'eclisse non renda l'altezza per mostrare che si espande per adattarsi; tuttavia, quando effettivamente eseguite questa operazione su un dispositivo, rende correttamente e fornisce il risultato desiderato. (alless per me)

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

    Tutti lo fanno in modo programmato, così ho pensato che questa risposta sarebbe stata perfettamente in questa sede. Questo codice ha funzionato per il mio nel xml. Im non pensare al rapporto ancora, ma ancora voluto porre questa risposta se avrebbe aiutato qualcuno.

     android:adjustViewBounds="true" 

    Saluti..

    Una soluzione molto semplice è quella di utilizzare le funzioni fornite da RelativeLayout .

    Ecco il xml che lo rende ansible con le visualizzazioni Android standard:

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

    Il trucco è che si imposta l' ImageView per riempire lo schermo, ma deve essere sopra gli altri layout. In questo modo si ottiene tutto ciò di cui avete bisogno.

    Stai impostando ScaleType su ScaleType.FIT_XY. Secondo il javadocs , questo allunga l'image per adattarsi all'intera area, cambiando il rapporto di aspetto se necessario. Questo spiegherebbe il comportmento che stai vedendo.

    Per get il comportmento desiderato … FIT_CENTER, FIT_START o FIT_END sono vicini, ma se l'image è più stretta di quella alta, non inizierà a riempire la width. Potresti vedere come sono stati implementati, e probabilmente dovresti capire come adattarla per il tuo scopo.

    ScaleType.CENTER_CROP farà quello che vuoi: allungare a width e scalare l'altezza di conseguenza. se l'altezza scalata supera i limiti dello schermo, l'image verrà ritagliata.

    Guarda c'è una soluzione molto più facile al tuo problema:

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

    È ansible utilizzare il mio StretchableImageView mantenendo il rapporto di aspetto (per width o per altezza) a seconda della width e dell'altezza del drawable:

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

    La sua semplice questione di impostare adjustViewBounds="true" e scaleType="fitCenter" nel file XML per ImageView!

     <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@drawable/image" android:adjustViewBounds="true" android:scaleType="fitCenter" /> 

    Nota: layout_width è impostato su match_parent

    Per me l'android: scaleType = "centerCrop" non ha risolto il mio problema. In realtà ha ampliato ulteriormente l'image. Così ho provato con android: scaleType = "fitXY" e ha funzionato eccellente.

    Questo funziona bene secondo il mio requisito

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

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.