Posizionamento / sovrapposizione (z-index) una vista sopra un'altra vista in Android


230

Ho un layout lineare che consiste in visualizzazione di immagini e visualizzazione di testo, uno sotto l'altro in un layout lineare.

<LinearLayout android:orientation="horizontal" ... >
 <ImageView 
     android:id="@+id/thumbnail"
     android:layout_weight="0.8" 
     android:layout_width="0dip"
     android:layout_height="fill_parent">
 </ImageView>
 <TextView 
    android:id="@+id/description"
    android:layout_weight="0.2"
    android:layout_width="0dip"
    android:layout_height="wrap_content">
 </TextView>

Alcune regole potrebbero mancare, questo per dare un'idea di come appare il layout. Voglio un'altra piccola visualizzazione testuale di dire 50dip in lunghezza e larghezza, posizionata sopra l'immagine visualizzata, per "sopra" intendevo z-index più che immagine immagine, voglio posizionarla al centro e sopra (sovrapponendo) l'immagine vista.

Voglio sapere come possiamo posizionare una vista sopra l'altra, con un indice z variabile (preferibilmente in layout lineare)?

Risposte:


295

Non puoi usare un LinearLayout per questo, ma puoi usare un FrameLayout. In a FrameLayout, l'indice z è definito dall'ordine in cui gli elementi vengono aggiunti, ad esempio:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/my_drawable"
        android:scaleType="fitCenter"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|center"
        android:padding="5dp"
        android:text="My Label"
        />
</FrameLayout>

In questo caso, TextView verrebbe disegnato sulla parte superiore di ImageView, lungo la parte inferiore centrale dell'immagine.


Sì, l'ho fatto usando il layout del frame stesso dopo aver esaminato la documentazione. Grazie.
sabato

11
C'è un vantaggio nell'usare FrameLayout invece RelativeLayout per questo?
Ixx,

12
FrameLayout non si riferisce ad altre viste nel gruppo, ma le sovrappone solo rispetto al genitore. RelativeLayout è più per il posizionamento rispetto ad altri elementi.
Kevin Coppock,

3
Ciao kcoppock il mio cellulare (hdpi) non rispetta l'ordine z nel layout del frame, ma ne ho un altro (xhdpi) e rispetto questo ordine, sai perché farlo? Grazie in anticipo! : D
Merlí Escarpenter Pérez,

1
A partire da API 21 / KitKat ora puoi usare setZ e translationZ; l'hack FrameLayout non è più necessario (finalmente!). Questo dovrebbe essere la risposta preferita per lo sviluppo 5.0+ moderna: stackoverflow.com/a/29703860/358578
pbarranis

183

3
possiamo usarlo anche nei file xml?
Annunci

2
Stavo cercando qualcosa di simile per far sì che il mio punto di vista cambiasse itz zindex durante l'animazione della traduzione.
DeltaCap019,

Potresti trovare una soluzione per l'animazione della traduzione?
nAkhmedov,

9
bringChildToFront () cambia solo l'indice della Vista all'interno del suo genitore
Zar E Ahmer,

4
questo
rovina

66

RelativeLayout funziona allo stesso modo, vince l'ultima immagine nel layout relativo.


14
A meno che non si usi l'elevazione, è necessario anche il valore più grande.
Sami Kuhmonen,

5
A questa domanda è stata posta una risposta prima che esistesse l'elevazione. L'uso dell'elevazione non risolverà il problema se la tua app ha un minSdk inferiore a Lollipop (sui telefoni pre-lollipop il layout apparirà errato se fai affidamento solo sull'elevazione) - devi comunque prestare attenzione all'ordine del layout. Hai ragione però che se usi l'elevazione sul componente inferiore, devi sicuramente avere almeno lo stesso o più in alto.
Jt-Gilkeson,

27

Modifica dell'ordine di sorteggio

Un'alternativa è cambiare l'ordine in cui le viste sono disegnate dal genitore. È possibile abilitare questa funzione da ViewGroup chiamando setChildrenDrawingOrderEnabled (true) e sovrascrivendo getChildDrawingOrder (int childCount, int i) .

Esempio:

/**
 * Example Layout that changes draw order of a FrameLayout
 */
public class OrderLayout extends FrameLayout {

    private static final int[][] DRAW_ORDERS = new int[][]{
            {0, 1, 2},
            {2, 1, 0},
            {1, 2, 0}
    };

    private int currentOrder;

    public OrderLayout(Context context) {
        super(context);
        setChildrenDrawingOrderEnabled(true);
    }

    public void setDrawOrder(int order) {
        currentOrder = order;
        invalidate();
    }

    @Override
    protected int getChildDrawingOrder(int childCount, int i) {
        return DRAW_ORDERS[currentOrder][i];
    }
}

Produzione:

La chiamata OrderLayout#setDrawOrder(int)con 0-1-2 comporta:

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine


Chiamate setDrawOrder (i) in onCreate () dell'attività? Se ho 6 widget nel mio XML, devo inizializzare ogni riga di DRAW_ORDERS con un array di 6 numeri (0-5)?
John Ward,

@JohnWard il layout mostrato sopra è solo a scopo esemplificativo, è possibile definire il proprio comportamento in getChildDrawingOrder ().
Tobrun,

ecco un post correlato con un codice molto chiaro: stackoverflow.com/questions/20524162/framelayout-in-reverse
Robert

20

Puoi utilizzare a view.setZ(float)partire dal livello API 21. Qui puoi trovare maggiori informazioni.


3
Questa dovrebbe ora essere la risposta preferita per API 21 / KitKat / 5.0 o successive. Per fortuna il vecchio hack di frameLayout non è più necessario. Personalmente non capisco la differenza tra setZ e translationZ, ma quest'ultimo è un attributo e ha funzionato magnificamente per me. Grazie!
pbarranis,

Per le precedenti API puoi usare anche ViewCompat # setZ ().
Ali Yucel Akgul,

@AliYucelAkgul se guardi i documenti qui , puoi vedere Compatibility: API < 21: No-op . Quindi penso che non funzionerà
Vadim Kotov,

@VadimKotov, ho provato nella mia app e funziona.
Ali Yucel Akgul,

@AliYucelAkgul bene, è strano. Forse un errore nella documentazione? Sei sicuro al 100% che funzioni con API <21? Ho un'idea che possa cambiare l'ordine delle viste per le precedenti API, ma niente cose fantasiose come l'elevazione, ecc.
Vadim Kotov

14

Ho risolto lo stesso problema aggiungendo android:elevation="1dp"a quale vista lo desideri su un altro. Ma non può essere visualizzato sotto 5.0 e avrà una piccola ombra, se puoi accettarlo, va bene.

Quindi, la soluzione più corretta che è @kcoppock ha detto.


7

Prova questo in un RelativeLayout:

ImageView image = new ImageView(this);
image.SetZ(float z);

Per me funziona.


2
Dovresti spiegare un po 'meglio. Ad esempio, dove inseriresti questo codice?
DevB2F

Bene, l'ho messo nel metodo OnCreate (). Ogni immagine aggiunta ha un indice z di preferenza rispetto a quelli aggiunti in precedenza. Voglio dire, attraverso l'indice z posso cambiare la posizione del prossimo dietro il precedente.
Rizzo,

5

C'è un modo per usare LinearLayout. Basta impostare marginTop dell'elemento precedente sul valore negativo corrispondente e assicurarsi che l'elemento desiderato in alto sia dopo l'elemento desiderato in basso nel proprio XML.

<linearLayout android:orientation="horizontal" ... >
<ImageView 
 android:id="@+id/thumbnail"
 android:layout_weight="0.8" 
 android:layout_width="0dip"
 android:layout_height="fill_parent"
>
</ImageView>
<TextView 
android:id="@+id/description"
android:layout_marginTop="-20dip"
android:layout_weight="0.2"
android:layout_width="0dip"
android:layout_height="wrap_content"
>
</TextView>

4

AFAIK non puoi farlo con layout lineari, dovrai fare un RelativeLayout .


RelativeLayout non estende frameLayout, sei sicuro che funzionerà?
ekatz,

Lo farà. È possibile utilizzare qualsiasi FrameLayout o RelativeLayout. Ognuno ha modi diversi di posizionare le viste figlio. Consulta i documenti per saperne di più su questi layout.
Vincent Mimoun-Prat,

questa è la strada da percorrere
Albert James Teddy

0

Se si sta aggiungendo la vista a livello di codice, è possibile utilizzare yourLayout.addView(view, 1);

dove 1 is the index.


0

Lo uso, se vuoi che una sola vista sia portata in primo piano quando necessario:

containerView.bringChildToFront(topView);

containerView è il contenitore di viste da ordinare, topView è la vista che desidero avere la cima più in alto nel contenitore.

per più viste organizzare sta per usare setChildrenDrawingOrderEnabled (true) e sovrascrivere getChildDrawingOrder (int childCount, int i) come menzionato sopra.

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.