Розміщення / перекриття (z-індекс) подання над іншим видом в android


230

У мене лінійний макет, який складається з перегляду зображень і перегляду тексту, один під іншим у лінійному макеті.

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

Деякі правила можуть бути відсутніми, це полягає в уявленні, як виглядає макет. Я хочу ще одного невеликого перегляду тексту, скажімо, 50dp у довжину та ширину, розміщений над переглядом зображення, "over". Я мав на увазі z-індекс більше, ніж imageview, я хочу розмістити це, в центрі та вище (внахлест) перегляду зображення.

Я хочу знати, як ми можемо розмістити один вид над іншим, змінюючи z-індекс (бажано в лінійному макеті)?

Відповіді:


295

Ви не можете використовувати LinearLayout для цього, але ви можете використовувати FrameLayout. У a FrameLayoutz-індекс визначається порядком, в якому додаються елементи, наприклад:

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

У цьому випадку TextView буде намальовано вгорі ImageView, уздовж нижнього центру зображення.


Так, я це зробив, використовуючи сам макет кадру після перегляду документації. Дякую.
сів

11
Чи є перевага використовувати для цього FrameLayout замість RelativeLayout?
Ixx

12
FrameLayout не стосується інших поглядів у групі, він просто розшаровує їх стосовно батьків. RelativeLayout - це більше для позиціонування щодо інших елементів.
Кевін Коппок

3
Привіт kcoppock, мій мобільний (hdpi) не дотримується z-порядку в макеті кадру, але у мене є інший (xhdpi) і поважаю це замовлення, чи знаєте ви, чому це робите? Спасибі заздалегідь! : D
Merlí Escarpenter Pérez

1
З API 21 / KitKat тепер ви можете використовувати setZ та translationZ; злом FrameLayout більше не потрібен (нарешті!). Це повинно бути кращим рішенням для сучасного розвитку 5.0 і вище: stackoverflow.com/a/29703860/358578
pbarranis

183

3
чи можемо ми використовувати це також у файлах xml?
Оголошення

2
Я шукав щось таке, щоб підняти мій погляд на зміну itz zindex під час перекладу.
DeltaCap019

Не можете знайти рішення для анімації перекладу?
nAkhmedov

9
doneChildToFront () просто змінює індекс Перегляду всередині своєї батьківщини
Zar E Ahmer


66

RelativeLayout працює так само, виграє останнє зображення у відносному макеті.


14
Якщо ви не використовуєте висоту, то вам також потрібно найбільше значення в цьому.
Самі Кухмонен

5
Це питання було задано і відповіли до того, як існувало піднесення. Використання висоти не вирішить проблему, якщо ваш додаток має minSdk менше, ніж Lollipop (на телефонах, що перебувають на льодянику, макет буде виглядати неправильно, якщо ви покладаєтесь лише на висоту) - вам все одно доведеться звертати увагу на порядок компонування. Ви маєте рацію, що якщо ви використовуєте висоту на нижньому компоненті - вам обов'язково потрібно мати принаймні те саме або вище на верхній частині.
jt-gilkeson

27

Зміна порядку жеребкування

Альтернативою є зміна порядку, в якому думки малює батько. Ви можете ввімкнути цю функцію з ViewGroup, зателефонувавши setChildrenDrawingOrderEnabled (true) та перевівши getChildDrawingOrder (int childCount, int i) .

Приклад:

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

Вихід:

Дзвінки OrderLayout#setDrawOrder(int)з результатами 0-1-2:

введіть тут опис зображення введіть тут опис зображення введіть тут опис зображення


Ви називаєте setDrawOrder (i) в активності onCreate ()? Якщо у мене в xml є 6 віджетів, чи потрібно мені ініціалізувати кожен рядок DRAW_ORDERS з масивом з 6 чисел (0-5)?
Джон Уорд

@JohnWard макет, показаний вище, є виключно для прикладу, ви можете визначити власну поведінку в getChildDrawingOrder ().
Тобрун

ось пов’язаний пост із значно чітким кодом: stackoverflow.com/questions/20524162/framelayout-in-reverse
Роберт

20

Можна використовувати view.setZ(float)починаючи з рівня 21 API. Тут ви можете знайти більше інформації.


3
Тепер це має бути кращою відповіддю для API 21 / KitKat / 5.0 або новішої версії. Старий хакер FrameLayout, на щастя, більше не потрібен. Особисто я не розумію різниці між setZ і translationZ, але останній є атрибутом і прекрасно працював для мене. Дякую!
pbarranis

Для попереднього apis ви також можете використовувати ViewCompat # setZ ().
Алі Юсель Акгул

@AliYucelAkgul якщо подивитися документи тут , ви можете побачити Compatibility: API < 21: No-op . Тому я думаю, що це не вийде
Вадим Котов

@VadimKotov, я спробував у своєму додатку, і він просто працює.
Алі Юсель Акгул

@AliYucelAkgul добре, це дивно. Можливо помилка в документах? Ви на 100% впевнені, що він працює для API <21? У мене є ідея, що вона може змінити порядок переглядів попередніх API, але немає таких фантазійних речей, як висота тощо.
Ватов Котов

14

Я вирішив ту саму проблему додаванням android:elevation="1dp" до якого виду ви хочете її над іншим. Але він не може відображатись нижче 5,0, і він матиме трохи тіні, якщо ви можете це прийняти, це нормально.

Отже, найбільш правильне рішення - це @kcoppock.


7

Спробуйте це у відносному макеті:

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

Це працює для мене.


2
Вам слід пояснити трохи краще. Наприклад, куди ви поставите цей код?
DevB2F

Ну, я помістив його в метод OnCreate (). Кожне додане зображення має z-індекс переваги над тими, що додавалися раніше. Я маю на увазі, через індекс z я можу змінити позицію наступного позаду попереднього.
Ріццо

5

Існує спосіб використання LinearLayout. Просто встановіть marginTop вашого попереднього елемента відповідним від’ємним значенням і переконайтеся, що елемент, який ви хочете зверху, знаходиться після того, як елемент, який ви хочете нижче, у вашому 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 ви не можете зробити це з лінійними макетами, вам доведеться піти на відносну макет .


RelativeLayout не розширює frameLayout, ви впевнені, що він буде працювати?
ekatz

Це буде. Ви можете використовувати будь-який FrameLayout або RelativeLayout. Кожен має різні способи розміщення дитячих поглядів. Щоб дізнатися більше про ці макети, зверніться до документів.
Вінсент Мімон-Прат



0

Я використовую це, якщо ви хочете, щоб при необхідності було виведено лише один вид:

containerView.bringChildToFront(topView);

containerView - це контейнер переглядів, який слід сортувати, topView - це перегляд, який я хочу мати як верхній у контейнері.

для влаштування кількох переглядів збирається використовувати setChildrenDrawingOrderEnabled (true) та переосмислити getChildDrawingOrder (int childCount, int i), як згадувалося вище.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.