Platzieren / Überlappen (Z-Index) einer Ansicht über einer anderen Ansicht in Android

229

Ich habe ein lineares Layout, das aus Bildansicht und Textansicht besteht, untereinander in einem linearen Layout.

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

Möglicherweise fehlen einige Regeln. Dies soll eine Vorstellung davon geben, wie das Layout aussieht. Ich möchte eine weitere kleine Textansicht von beispielsweise 50 Dip in Länge und Breite, die über der Bildansicht platziert ist. Mit "über" meine ich Z-Index mehr als Bildansicht. Ich möchte dies in der Mitte und über (überlappend) der Bildansicht platzieren.

Ich möchte wissen, wie wir eine Ansicht mit variierendem Z-Index (vorzugsweise im linearen Layout) über der anderen platzieren können.

saß
quelle

Antworten:

294

Sie können hierfür kein LinearLayout verwenden, aber Sie können ein FrameLayout. In a FrameLayoutwird der Z-Index durch die Reihenfolge definiert, in der die Elemente hinzugefügt werden, zum Beispiel:

<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 diesem Fall wird die Textansicht über der Bildansicht in der unteren Bildmitte gezeichnet.

Kevin Coppock
quelle
Ja, ich habe es mit dem Rahmenlayout selbst gemacht, nachdem ich die Dokumentation durchgesehen habe. Danke dir.
saß am
11
Gibt es einen Vorteil, wenn Sie dafür FrameLayout anstelle von RelativeLayout verwenden?
Ixx
12
FrameLayout bezieht sich nicht auf andere Ansichten in der Gruppe, sondern überlagert sie nur in Bezug auf das übergeordnete Element. RelativeLayout dient eher zur Positionierung relativ zu anderen Elementen.
Kevin Coppock
3
Hallo kcoppock, mein Handy (hdpi) respektiert die Z-Reihenfolge im Rahmenlayout nicht, aber ich habe eine andere (xhdpi) und respektiere diese Reihenfolge. Weißt du, warum das so ist? Danke im Voraus! : D
Merlí Escarpenter Pérez
1
Ab API 21 / KitKat können Sie jetzt setZ und translationZ verwenden. Der FrameLayout-Hack wird (endlich!) nicht mehr benötigt. Dies sollte die bevorzugte Antwort für die moderne 5.0+ Entwicklung sein: stackoverflow.com/a/29703860/358578
pbarranis
183

Probieren Sie Folgendes aus .bringToFront():

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

DIYismus
quelle
3
Können wir dies auch in XML-Dateien verwenden?
Anzeigen
2
Ich habe nach etwas gesucht, um meine Ansicht dazu zu bringen, den itz zindex während der Übersetzungsanimation zu ändern.
DeltaCap019
Könnten Sie eine Lösung für Übersetzungsanimationen finden?
nAkhmedov
9
bringChildToFront () ändert nur den Index der Ansicht in seinem übergeordneten Element
Zar E Ahmer
4
Dies
verschraubt
66

RelativeLayout funktioniert genauso, das letzte Bild im relativen Layout gewinnt.

jt-gilkeson
quelle
14
Wenn Sie keine Höhe verwenden, benötigen Sie auch den größten Wert.
Sami Kuhmonen
5
Diese Frage wurde gestellt und beantwortet, bevor es eine Erhebung gab. Die Verwendung der Höhe behebt das Problem nicht, wenn Ihre App einen minSdk weniger als Lollipop hat (auf Telefonen vor Lollipop sieht das Layout falsch aus, wenn Sie sich nur auf die Höhe verlassen) - Sie müssen immer noch auf die Reihenfolge des Layouts achten. Sie haben jedoch Recht, wenn Sie die Höhe für die untere Komponente verwenden, müssen Sie auf der Oberseite mindestens die gleiche oder eine höhere Höhe haben.
Jt-Gilkeson
27

Zeichnungsreihenfolge ändern

Eine Alternative besteht darin, die Reihenfolge zu ändern, in der die Ansichten vom übergeordneten Element gezeichnet werden. Sie können diese Funktion in ViewGroup aktivieren, indem Sie setChildrenDrawingOrderEnabled (true) aufrufen und getChildDrawingOrder (int childCount, int i) überschreiben .

Beispiel:

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

Ausgabe:

Ein Anruf OrderLayout#setDrawOrder(int)mit 0-1-2 führt zu:

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Tobrun
quelle
Rufen Sie setDrawOrder (i) in onCreate () der Aktivität auf? Wenn ich 6 Widgets in meiner XML habe, muss ich jede Zeile von DRAW_ORDERS mit einem Array von 6 Zahlen (0-5) initialisieren?
John Ward
@JohnWard das oben gezeigte Layout dient nur zu Beispielzwecken. Sie können Ihr eigenes Verhalten in getChildDrawingOrder () definieren.
Tobrun
Hier ist ein verwandter Beitrag mit viel klarem Code: stackoverflow.com/questions/20524162/framelayout-in-reverse
Robert
20

Sie können verwenden view.setZ(float) ab API-Level 21 verwenden. Hier finden Sie weitere Informationen.

Vadim Kotov
quelle
3
Dies sollte nun die bevorzugte Antwort für API 21 / KitKat / 5.0 oder höher sein. Der alte frameLayout-Hack wird zum Glück nicht mehr benötigt. Persönlich verstehe ich den Unterschied zwischen setZ und translationZ nicht, aber letzteres ist ein Attribut und hat für mich wunderbar funktioniert. Vielen Dank!
Pbarranis
Für die vorherigen APIs können Sie auch ViewCompat # setZ () verwenden.
Ali Yucel Akgul
@AliYucelAkgul Wenn Sie sich die Dokumente hier ansehen , können Sie sehen Compatibility: API < 21: No-op . Also ich denke es wird nicht funktionieren
Vadim Kotov
@VadimKotov, ich habe es in meiner App versucht und es funktioniert einfach.
Ali Yucel Akgul
@AliYucelAkgul gut, das ist seltsam. Vielleicht ein Fehler in den Dokumenten? Sind Sie zu 100% sicher, dass es für API <21 funktioniert? Ich habe eine Idee, dass es die Reihenfolge der Ansichten für die vorherigen APIs ändern kann, aber keine ausgefallenen Dinge wie Elevation, etc.
Vadim Kotov
14

Ich habe das gleiche Problem gelöst, indem ich hinzugefügt habe, android:elevation="1dp"zu welcher Ansicht Sie es über eine andere Ansicht möchten. Aber es kann nicht unter 5.0 angezeigt werden und es wird einen kleinen Schatten haben. Wenn Sie es akzeptieren können, ist es in Ordnung.

Also, die richtigste Lösung, die @kcoppock ist, sagte.

dreißig Yuan
quelle
7

Versuchen Sie dies in einem RelativeLayout:

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

Für mich geht das.

Rizzo
quelle
2
Du solltest es etwas besser erklären. Wo würden Sie zum Beispiel diesen Code ablegen?
DevB2F
Nun, ich habe es in die OnCreate () -Methode eingefügt. Jedes hinzugefügte Bild hat einen bevorzugten Z-Index gegenüber den zuvor hinzugefügten. Ich meine, durch den z-Index kann ich die Position des nächsten hinter dem vorherigen ändern.
Rizzo
5

Es gibt eine Möglichkeit, LinearLayout zu verwenden. Setzen Sie einfach den marginTop Ihres vorherigen Elements auf den entsprechenden negativen Wert und stellen Sie sicher, dass das Element, das Sie oben haben möchten, hinter dem Element steht, das Sie unten in Ihrem XML haben möchten.

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

AFAIK Sie können es nicht mit linearen Layouts tun, Sie müssen sich für ein RelativeLayout entscheiden .

Vincent Mimoun-Prat
quelle
RelativeLayout erweitert frameLayout nicht. Sind Sie sicher, dass es funktionieren wird?
Ekatz
Es wird. Sie können jedes FrameLayout oder RelativeLayout verwenden. Jedes hat unterschiedliche Möglichkeiten, untergeordnete Ansichten zu platzieren. Weitere Informationen zu diesen Layouts finden Sie in den Dokumenten.
Vincent Mimoun-Prat
Dies ist der richtige Weg
Albert James Teddy
0

Wenn Sie die Ansicht programmgesteuert hinzufügen, können Sie sie verwenden yourLayout.addView(view, 1);

wo 1 is the index.

Alexander Maslew
quelle
0

Ich verwende dies, wenn Sie möchten, dass bei Bedarf nur eine Ansicht nach vorne gebracht wird:

containerView.bringChildToFront(topView);

containerView ist der Container mit zu sortierenden Ansichten, topView ist eine Ansicht, die ich am häufigsten im Container haben möchte.

Wenn mehrere Ansichten angeordnet werden sollen, müssen Sie setChildrenDrawingOrderEnabled (true) verwenden und getChildDrawingOrder (int childCount, int i) wie oben erwähnt überschreiben.

Milan Jurkulak
quelle