Umieszczanie / nakładanie (indeks Z) widoku nad innym widokiem w Androidzie

230

Mam układ liniowy, który składa się z podglądu obrazu i tekstu, jeden pod drugim w układzie liniowym.

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

Może brakować niektórych zasad, aby dać wyobrażenie o tym, jak wygląda układ. Chcę inny mały widok tekstu, powiedzmy 50dip długości i szerokości, umieszczony nad widokiem obrazu, przez „ponad” Miałem na myśli indeks Z bardziej niż widok obrazu, chcę to umieścić, pośrodku i powyżej (nakładając się) widoku obrazu.

Chcę wiedzieć, jak możemy umieścić jeden widok nad drugim, z różnym indeksem Z (najlepiej w układzie liniowym)?

sob
źródło

Odpowiedzi:

295

Nie możesz do tego użyć LinearLayout, ale możesz użyć FrameLayout. W FrameLayoutindeksie z jest określony przez kolejność dodawania elementów, na przykład:

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

W tym przypadku TextView zostanie narysowany na górze ImageView, wzdłuż dolnej środkowej części obrazu.

Kevin Coppock
źródło
Tak, zrobiłem to używając samego układu ramki po przejrzeniu dokumentacji. Dziękuję Ci.
sob.
11
Czy istnieje korzyść z użycia FrameLayout zamiast RelativeLayout?
Ixx
12
FrameLayout nie odnosi się do innych widoków w grupie, po prostu nakłada je na warstwy względem rodzica. RelativeLayout służy bardziej do pozycjonowania względem innych elementów.
Kevin Coppock,
3
Cześć kcoppock mój telefon komórkowy (HDpi) nie przestrzega kolejności Z w układzie ramki, ale mam inną (XHDpi) i przestrzegam tej kolejności, czy wiesz, dlaczego to robisz? Z góry dziękuję! : D
Merlí Escarpenter Pérez
1
Od API 21 / KitKat możesz teraz używać setZ i translationZ; hack FrameLayout nie jest już potrzebny (wreszcie!). To powinna być preferowana odpowiedź dla współczesnych wersji 5.0+: stackoverflow.com/a/29703860/358578
pbarranis
183

Spróbuj .bringToFront():

http://developer.android.com/reference/android/view/View.html#bringToFront%28%29

diyizm
źródło
3
czy możemy tego również użyć w plikach XML?
Reklamy
2
Szukałem czegoś takiego, aby mój widok zmienił itz zindex podczas animacji tłumaczenia.
DeltaCap019,
Czy możesz znaleźć rozwiązanie dla animacji tłumaczenia?
nAkhmedov
9
bringChildToFront () po prostu zmienia indeks widoku wewnątrz swojego obiektu nadrzędnego
Zar E Ahmer
4
to
psuje
66

RelativeLayout działa w ten sam sposób, wygrywa ostatni obraz w układzie względnym.

jt-gilkeson
źródło
14
O ile nie użyjesz wysokości, potrzebujesz również największej wartości.
Sami Kuhmonen,
5
To pytanie zostało zadane i udzielone przed powstaniem wzniesienia. Użycie podniesienia nie rozwiąże problemu, jeśli Twoja aplikacja ma minSdk mniejszy niż Lollipop (w telefonach z wersją wcześniejszą niż Lollipop układ będzie wyglądał źle, jeśli polegasz tylko na podniesieniu) - nadal musisz zwracać uwagę na kolejność układu. Masz jednak rację, że jeśli używasz elewacji na dolnym elemencie - zdecydowanie musisz mieć co najmniej taki sam lub wyższy na górze.
jt-gilkeson
27

Zmiana kolejności losowania

Alternatywą jest zmiana kolejności rysowania widoków przez element nadrzędny. Możesz włączyć tę funkcję w ViewGroup, wywołując setChildrenDrawingOrderEnabled (true) i zastępując getChildDrawingOrder (int childCount, int i) .

Przykład:

/**
 * 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];
    }
}

Wynik:

Wywołanie OrderLayout#setDrawOrder(int)z 0-1-2 powoduje:

wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

Tobrun
źródło
Czy wywołujesz funkcję setDrawOrder (i) w funkcji onCreate () działania? Jeśli mam 6 widżetów w swoim pliku XML, czy muszę inicjować każdy wiersz DRAW_ORDERS tablicą 6 liczb (0-5)?
John Ward,
@JohnWard pokazany powyżej układ służy wyłącznie przykładowym celom, możesz zdefiniować własne zachowanie w getChildDrawingOrder ().
Tobrun
Oto powiązany post z bardzo wyraźnym kodem: stackoverflow.com/questions/20524162/framelayout-in-reverse
Robert
20

Możesz użyć, view.setZ(float)zaczynając od poziomu API 21. Tutaj możesz znaleźć więcej informacji.

Wadim Kotow
źródło
3
To powinna być teraz preferowana odpowiedź dla API 21 / KitKat / 5.0 lub wyższej. Na szczęście stary hack frameLayout nie jest już wymagany. Osobiście nie rozumiem różnicy między setZ a translationZ, ale ten ostatni jest atrybutem i działał dla mnie pięknie. Dzięki!
pbarranis
W poprzednich apisach możesz także użyć ViewCompat # setZ ().
Ali Yucel Akgul
@AliYucelAkgul, jeśli spojrzysz na dokumenty tutaj , możesz zobaczyć Compatibility: API < 21: No-op . Myślę więc, że to nie zadziała
Vadim Kotov
@VadimKotov, próbowałem w mojej aplikacji i to po prostu działa.
Ali Yucel Akgul
@AliYucelAkgul dobrze, to dziwne. Może błąd w dokumentacji? Czy jesteś w 100% pewien, że działa dla API <21? Mam pomysł, że może zmienić kolejność widoków dla poprzednich interfejsów API, ale nie ma żadnych wymyślnych rzeczy, takich jak elewacja itp.
Vadim Kotov,
14

Rozwiązałem ten sam problem, dodając android:elevation="1dp"do którego widoku chcesz go nad innym. Ale nie może wyświetlić poniżej 5.0 i będzie miał trochę cienia, jeśli możesz to zaakceptować, jest w porządku.

Więc najbardziej poprawne rozwiązanie, które jest @kcoppock powiedział.

trzydzieści juanów
źródło
7

Spróbuj tego w RelativeLayout:

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

Mi to pasuje.

Rizzo
źródło
2
Powinieneś wyjaśnić trochę lepiej. Na przykład gdzie możesz umieścić ten kod?
DevB2F,
Cóż, umieściłem go w metodzie OnCreate (). Każde dodane zdjęcie ma indeks preferencji Z względem dodanych wcześniej. Mam na myśli, że poprzez indeks Z mogę zmienić pozycję następnego za poprzednim.
Rizzo
5

Istnieje sposób użycia LinearLayout. Po prostu ustaw marginTop poprzedniego elementu na odpowiednią wartość ujemną i upewnij się, że element, który chcesz na górze, znajduje się za elementem, który chcesz poniżej w pliku 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>
Tim
źródło
4

AFAIK, że nie możesz tego zrobić z układami liniowymi, musisz wybrać RelativeLayout .

Vincent Mimoun-Prat
źródło
RelativeLayout nie rozszerza frameLayout, czy jesteś pewien, że zadziała?
ekatz
To będzie. Możesz użyć dowolnego z FrameLayout lub RelativeLayout. Każdy z nich ma inne sposoby umieszczania widoków dzieci. Zapoznaj się z dokumentacją, aby dowiedzieć się więcej o tych układach.
Vincent Mimoun-Prat
to jest najlepsza droga
Albert James Teddy
0

Jeśli programowo dodajesz widok, możesz użyć yourLayout.addView(view, 1);

gdzie 1 is the index.

Alexander Maslew
źródło
0

Używam tego, jeśli chcesz, aby w razie potrzeby wyświetlać tylko jeden widok:

containerView.bringChildToFront(topView);

containerView to kontener widoków do posortowania, topView to widok, który chcę mieć jako najwyższy w kontenerze.

dla wielu widoków do aranżacji ma zamiar użyć setChildrenDrawingOrderEnabled (true) i nadpisanie getChildDrawingOrder (int childCount, int i), jak wspomniano powyżej.

Milan Jurkulak
źródło