Android: ridimensionare un disegno o un'immagine di sfondo?


134

Su un layout voglio ridimensionare l'immagine di sfondo (mantenendo le proporzioni) allo spazio allocato quando viene creata la pagina. Qualcuno ha idea di come farlo?

Sto usando layout.setBackgroundDrawable()e a BitmapDrawable()per impostare il gravityritaglio e il riempimento, ma non vedo alcuna opzione per il ridimensionamento.


Ho avuto questo problema e ho seguito la raccomandazione di Dweebo con la modifica suggerita da Anke: cambiato fitXY in fitCenter. Ha funzionato bene

Risposte:


90

Per personalizzare il ridimensionamento delle immagini di sfondo, crea una risorsa come questa:

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:gravity="center"
    android:src="@drawable/list_bkgnd" />

Quindi verrà centrato nella vista se utilizzato come sfondo. Ci sono anche altri flag: http://developer.android.com/guide/topics/resources/drawable-resource.html


6
Ho provato a usare bitmap ma l'immagine è semplicemente centrata, non ridimensionata come chiede Sam. Quando uso ImageView, funziona magnificamente, senza problemi. (nb: anche io non sto scorrendo nel mio caso.) Con cosa aumenterei la bitmap per ridimensionare l'immagine?
Joe D'Andrea,

7
I valori possibili sono: "top" | "fondo" | "sinistra" | "giusto" | "center_vertical" | "fill_vertical" | "center_horizontal" | "fill_horizontal" | "centro" | "riempire" | "clip_vertical" | "clip_horizontal"
Aleks N.

30
nessuno di questi parametri scala la bitmap, mantenendo la sua proporzione, quindi la risposta è sbagliata.
Malachiasz,

7
Caro Malachiasz, il "centro" rispetta le proporzioni. Ma non ridimensionerà l'immagine. Ciò significa che è una caratteristica un po 'pericolosa da usare. A seconda della risoluzione del bersaglio non si sa mai quanto in scala la cosa verrà fuori esattamente. Un'altra soluzione per metà di Google.

2
hai un modo per aggiungere l'attributo scaleType?
ademar111190,

57

Non ho provato a fare esattamente quello che vuoi, ma puoi ridimensionare un ImageView usando android:scaleType="fitXY"
e sarà ridimensionato per adattarsi a qualsiasi dimensione che dai a ImageView.

Quindi puoi creare un FrameLayout per il tuo layout, inserire ImageView al suo interno e quindi qualsiasi altro contenuto di cui hai bisogno nel FrameLayout con uno sfondo trasparente.

<FrameLayout  
android:layout_width="fill_parent" android:layout_height="fill_parent">

  <ImageView 
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:src="@drawable/back" android:scaleType="fitXY" />

  <LinearLayout>your views</LinearLayout>
</FrameLayout>

1
È possibile farlo su una superficie. In caso contrario, posso mostrare l'anteprima (per un'app di registrazione) usando FrameLayout?
Namratha,

1
@dweebo: hai provato questo? Non sembra funzionare per me.
speedplane il

3
Sottovalutato dal momento che l'utilizzo di due componenti dell'interfaccia utente anziché uno è una cattiva idea soprattutto per componenti occupati come ListView. Molto probabilmente avrai problemi durante lo scorrimento. Soluzione corretta: stackoverflow.com/a/9362168/145046
Aleks N.

Ho provato un scaleType di fitCenter e centerCrop (insieme ad alcune varianti del disegno / immagine per diverse densità) e ha funzionato! Entrambi i tipi di scala avevano senso per me - sospetto più che altro una preferenza personale basata sull'immagine. Nota che ho usato merge invece di FrameLayout e non c'è scorrimento nel mio caso particolare.
Joe D'Andrea,

2
centerInside è corretto, non fitXY, poiché fitXY non mantiene le proporzioni dell'immagine
Malachiasz,

35

C'è un modo semplice per farlo dal drawable:

your_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item android:drawable="@color/bg_color"/>
    <item>
        <bitmap
            android:gravity="center|bottom|clip_vertical"
            android:src="@drawable/your_image" />
    </item>

</layer-list>

L'unico aspetto negativo è che se non c'è abbastanza spazio, la tua immagine non verrà mostrata completamente, ma sarà ritagliata, non potrei trovare un modo per farlo direttamente da un disegno. Ma dai test che ho fatto funziona abbastanza bene e non ritaglia gran parte dell'immagine. Puoi giocare di più con le opzioni di gravità.

Un altro modo sarà quello di creare solo un layout, dove potrete utilizzare un ImageViewe impostare l' scaleTypea fitCenter.


2
Questa soluzione è sicuramente quella che stavo cercando da molto tempo per sostituire la proprietà di sfondo del mio tema ed evitare la scala dell'immagine in modo diverso quando la vista ha schede o meno. Grazie per averlo condiviso.
Bibu,

1
Mostra errore:error: <item> must have a 'name' attribute.
Dmitry

grazie @lonutNegru, +1 per avermi salvato la giornata :)
Ravi Vaniya il

18

Per mantenere le proporzioni devi usare android:scaleType=fitCentero fitStartecc. L'uso fitXYnon manterrà le proporzioni originali dell'immagine!

Nota che funziona solo per le immagini con un srcattributo, non per l'immagine di sfondo.


18

Usa l'immagine come sfondo per il layout:

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

    <ImageView
        android:id="@+id/imgPlaylistItemBg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:adjustViewBounds="true"
        android:maxHeight="0dp"
        android:scaleType="fitXY"
        android:src="@drawable/img_dsh" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >


    </LinearLayout>

</FrameLayout>

Grazie! android:scaleType="centerCrop"Funziona anche .
CoolMind

5

Quando si imposta il Drawable di un ImageView utilizzando il setBackgroundDrawablemetodo, l'immagine verrà sempre ridimensionata. I parametri come adjustViewBoundso diversi ScaleTypesverranno semplicemente ignorati. L'unica soluzione per mantenere le proporzioni che ho trovato è ridimensionare ImageViewdopo aver caricato il disegno. Ecco lo snippet di codice che ho usato:

// bmp is your Bitmap object
int imgHeight = bmp.getHeight();
int imgWidth = bmp.getWidth();
int containerHeight = imageView.getHeight();
int containerWidth = imageView.getWidth();
boolean ch2cw = containerHeight > containerWidth;
float h2w = (float) imgHeight / (float) imgWidth;
float newContainerHeight, newContainerWidth;

if (h2w > 1) {
    // height is greater than width
    if (ch2cw) {
        newContainerWidth = (float) containerWidth;
        newContainerHeight = newContainerWidth * h2w;
    } else {
        newContainerHeight = (float) containerHeight;
        newContainerWidth = newContainerHeight / h2w;
    }
} else {
    // width is greater than height
    if (ch2cw) {
        newContainerWidth = (float) containerWidth;
        newContainerHeight = newContainerWidth / h2w; 
    } else {
        newContainerWidth = (float) containerHeight;
        newContainerHeight = newContainerWidth * h2w;       
    }
}
Bitmap copy = Bitmap.createScaledBitmap(bmp, (int) newContainerWidth, (int) newContainerHeight, false);
imageView.setBackgroundDrawable(new BitmapDrawable(copy));
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
imageView.setLayoutParams(params);
imageView.setMaxHeight((int) newContainerHeight);
imageView.setMaxWidth((int) newContainerWidth);

Nel frammento di codice sopra è bmp l'oggetto Bitmap che deve essere mostrato e imageView è l' ImageViewoggetto

Una cosa importante da notare è la modifica dei parametri di layout . Ciò è necessario perché setMaxHeighte setMaxWidthfarà la differenza solo se la larghezza e l'altezza sono definite per avvolgere il contenuto, non per riempire il genitore. Riempi parent invece è l'impostazione desiderata all'inizio, perché altrimenti containerWidthe containerHeightavremo entrambi valori pari a 0. Quindi, nel tuo file di layout avrai qualcosa di simile per ImageView:

...
<ImageView android:id="@+id/my_image_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
...

4

Questa non è la soluzione più performante, ma come qualcuno ha suggerito invece di sfondo puoi creare FrameLayout o RelativeLayout e usare ImageView come sfondo pseudo - altri elementi saranno posizionati semplicemente sopra di esso:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent">

    <ImageView
        android:id="@+id/ivBackground"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:scaleType="fitStart"
        android:src="@drawable/menu_icon_exit" />

    <Button
        android:id="@+id/bSomeButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="61dp"
        android:layout_marginTop="122dp"
        android:text="Button" />

</RelativeLayout>

Il problema con ImageView è che solo scaleTypes disponibili sono: CENTER, CENTER_CROP, CENTER_INSIDE, FIT_CENTER, FIT_END, FIT_START, FIT_XY, MATRIX ( http://etcodehome.blogspot.de/2011/05//android-imageview-scaletype-samples.html )

e per "ridimensionare l'immagine di sfondo (mantenendo le proporzioni)" in alcuni casi, quando si desidera che un'immagine riempia l'intero schermo (ad esempio l'immagine di sfondo) e le proporzioni dello schermo siano diverse da quelle dell'immagine, il tipo di scala necessario è gentile di TOP_CROP, perché:

CENTER_CROP centra l'immagine in scala invece di allineare il bordo superiore a quello superiore della vista immagine e FIT_START si adatta all'altezza dello schermo e non riempie la larghezza. E come ha notato l'utente Anke, FIT_XY non mantiene le proporzioni.

Volentieri qualcuno ha esteso ImageView per supportare TOP_CROP

public class ImageViewScaleTypeTopCrop extends ImageView {
    public ImageViewScaleTypeTopCrop(Context context) {
        super(context);
        setup();
    }

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

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

    private void setup() {
        setScaleType(ScaleType.MATRIX);
    }

    @Override
    protected boolean setFrame(int frameLeft, int frameTop, int frameRight, int frameBottom) {

        float frameWidth = frameRight - frameLeft;
        float frameHeight = frameBottom - frameTop;

        if (getDrawable() != null) {

            Matrix matrix = getImageMatrix();
            float scaleFactor, scaleFactorWidth, scaleFactorHeight;

            scaleFactorWidth = (float) frameWidth / (float) getDrawable().getIntrinsicWidth();
            scaleFactorHeight = (float) frameHeight / (float) getDrawable().getIntrinsicHeight();

            if (scaleFactorHeight > scaleFactorWidth) {
                scaleFactor = scaleFactorHeight;
            } else {
                scaleFactor = scaleFactorWidth;
            }

            matrix.setScale(scaleFactor, scaleFactor, 0, 0);
            setImageMatrix(matrix);
        }

        return super.setFrame(frameLeft, frameTop, frameRight, frameBottom);
    }

}

https://stackoverflow.com/a/14815588/2075875

Ora IMHO sarebbe perfetto se qualcuno scrivesse un Drawable personalizzato che ridimensiona l'immagine in quel modo. Quindi potrebbe essere utilizzato come parametro di sfondo.


Reflog suggerisce di ridimensionare il disegno prima di usarlo. Ecco le istruzioni su come farlo: Java (Android): come ridimensionare un disegno senza Bitmap? Sebbene abbia uno svantaggio, quel drawable / bitmap ingrandito utilizzerà più RAM, mentre il ridimensionamento al volo usato da ImageView non richiede più memoria. Il vantaggio potrebbe essere un minor carico del processore.


Ben fatto! Fa esattamente quello che cercavo: immagine di sfondo per riempire l'intero schermo aumentando la larghezza in modo proporzionale e ritagliando il fondo dell'immagine.
CMash,

4

Il codice sottostante rende la bitmap perfettamente con le stesse dimensioni della visualizzazione dell'immagine. Ottieni l'altezza e la larghezza dell'immagine bitmap e quindi calcola la nuova altezza e larghezza con l'aiuto dei parametri di imageview. Che ti dà l'immagine richiesta con le migliori proporzioni.

int bwidth=bitMap1.getWidth();
int bheight=bitMap1.getHeight();
int swidth=imageView_location.getWidth();
int sheight=imageView_location.getHeight();
new_width=swidth;
new_height = (int) Math.floor((double) bheight *( (double) new_width / (double) bwidth));
Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap1,new_width,new_height, true);
imageView_location.setImageBitmap(newbitMap)

2

Cosa funziona Dweebo proposto. Ma a mio modesto parere non è necessario. Uno sfondo disegnabile si ridimensiona bene da solo. La vista dovrebbe avere larghezza e altezza fisse, come nell'esempio seguente:

 < RelativeLayout 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/black">

    <LinearLayout
        android:layout_width="500dip"
        android:layout_height="450dip"
        android:layout_centerInParent="true"
        android:background="@drawable/my_drawable"
        android:orientation="vertical"
        android:padding="30dip"
        >
        ...
     </LinearLayout>
 < / RelativeLayout>

2
La mia comprensione è che uno sfondo si espanderà per riempire una vista, ma non si ridurrà.
Edward Falk,

1

Un'opzione da provare è quella di mettere l'immagine nella drawable-nodpicartella e impostare lo sfondo di un layout sull'ID risorsa disegnabile.

Funziona sicuramente con il ridimensionamento, ma non ho provato con il ridimensionamento.


0

Kotlin:

Se è necessario disegnare una bitmap in una vista, ridimensionata su FIT.

È possibile eseguire i calcoli corretti per impostare bm l'altezza uguale al contenitore e regolare la larghezza, nel caso in cui il rapporto larghezza-altezza bm sia inferiore al rapporto larghezza-altezza del contenitore o l'inverso nello scenario opposto.

Immagini:

Immagine di esempio 1

Immagine di esempio 2

// binding.fragPhotoEditDrawCont is the RelativeLayout where is your view
// bm is the Bitmap
val ch = binding.fragPhotoEditDrawCont.height
val cw = binding.fragPhotoEditDrawCont.width
val bh = bm.height
val bw = bm.width
val rc = cw.toFloat() / ch.toFloat()
val rb = bw.toFloat() / bh.toFloat()

if (rb < rc) {
    // Bitmap Width to Height ratio is less than Container ratio
    // Means, bitmap should pin top and bottom, and have some space on sides.
    //              _____          ___
    // container = |_____|   bm = |___| 
    val bmHeight = ch - 4 //4 for container border
    val bmWidth = rb * bmHeight //new width is bm_ratio * bm_height
    binding.fragPhotoEditDraw.layoutParams = RelativeLayout.LayoutParams(bmWidth.toInt(), bmHeight)
}
else {
    val bmWidth = cw - 4 //4 for container border
    val bmHeight = 1f/rb * cw
    binding.fragPhotoEditDraw.layoutParams = RelativeLayout.LayoutParams(bmWidth, bmHeight.toInt())
}

-4

dovrai pre-ridimensionare quel disegno prima di usarlo come sfondo


È davvero l'unica opzione? Non esiste alcun tipo di contenitore per posizionare ImageView in cui è possibile specificare le dimensioni di visualizzazione?
GrkEngineer,

Ho anche problemi con SurfaceView
AZ_

3
Non c'è niente come adattamento aspetto, riempimento aspetto, in alto a sinistra, in alto ecc. Come su iOS? Che schifo ..
Maciej Swic,

Come ha detto @Aleksej, una risposta non vera.
studente

-5

Puoi usare uno dei seguenti:

Android: la gravità = "fill_horizontal | clip_vertical"

O

Android: la gravità = "fill_vertical | clip_horizontal"

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.