Размещение / перекрытие (z-index) вида над другим видом в 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>

Некоторые правила могут отсутствовать, чтобы дать представление о том, как выглядит макет. Я хочу еще одно небольшое текстовое представление, скажем, 50dip по длине и ширине, расположенное над изображением, под словом «над» я имел в виду z-index больше, чем изображение, я хочу разместить его в центре и выше (перекрывая) изображения.

Я хочу знать, как мы можем разместить одно представление над другим, с переменным 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
Мерли Эскарпентер Перес
1
С API 21 / KitKat теперь вы можете использовать setZ и translationZ; хакер FrameLayout больше не нужен (наконец-то!). Это должно быть предпочтительным ответом для современной разработки 5.0+: stackoverflow.com/a/29703860/358578
pbarranis
183

Попробуйте .bringToFront():

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

diyism
источник
3
мы можем использовать это в файлах XML тоже?
Объявления
2
Я искал что-то такое, чтобы привести свое мнение к изменению itz zindex во время анимации перевода.
DeltaCap019
Не могли бы вы найти решение для анимации перевода?
Ахмедов
9
Метод takeChildToFront () просто меняет индекс представления внутри своего родителя
Zar E Ahmer,
4
это винты весь порядок расположения
Джемшит Искендеров
66

RelativeLayout работает так же, последнее изображение в относительной компоновке выигрывает.

JT-gilkeson
источник
14
Если вы не используете возвышение, вам также потребуется наибольшее значение в этом.
Сами Кухмонен
5
Этот вопрос был задан и получен до того, как возникла высота. Использование повышения не решит проблему, если в вашем приложении minSdk меньше, чем Lollipop (на телефонах, предшествующих 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 приводит к:

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

Tobrun
источник
Вы вызываете setDrawOrder (i) в onCreate () действия? Если в моем XML есть 6 виджетов, нужно ли инициализировать каждую строку DRAW_ORDERS массивом из 6 чисел (0-5)?
Джон Уорд
@JohnWard макет, показанный выше, исключительно для примера, вы можете определить свое собственное поведение в getChildDrawingOrder ().
Тобрун
вот соответствующий пост с очень четким кодом: stackoverflow.com/questions/20524162/framelayout-in-reverse
Роберт,
20

Вы можете использовать, view.setZ(float)начиная с уровня API 21. Здесь вы можете найти больше информации.

Вадим Котов
источник
3
Теперь это должно быть предпочтительным ответом для API 21 / KitKat / 5.0 или выше. К счастью, старый взлом FrameLayout больше не требуется. Лично я не понимаю разницы между setZ и translationZ, но последний является атрибутом и прекрасно работает для меня. Спасибо!
pbarranis
Для предыдущего API вы также можете использовать ViewCompat # setZ ().
Али Юсель Акгул
@AliYucelAkgul если вы посмотрите документы здесь , вы можете увидеть Compatibility: API < 21: No-op . Поэтому я думаю, что это не сработает
Вадим Котов
@VadimKotov, я попробовал в своем приложении, и оно просто работает.
Али Юсель Акгул
@AliYucelAkgul хорошо, это странно. Может быть, ошибка в документах? Вы на 100% уверены, что он работает для API <21? У меня есть идея, что он может изменить порядок представлений для предыдущих API, но не такие причудливые вещи, как высота и т. Д.
Вадим Котов
14

Я решил ту же проблему, добавив android:elevation="1dp" в какой вид вы хотите его поверх другого. Но он не может отображаться ниже 5.0, и у него будет небольшая тень, если вы можете принять его, все в порядке.

Итак, самое правильное решение - @kcoppock.

thirtyyuan
источник
7

Попробуйте это в RelativeLayout:

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

Меня устраивает.

Rizzo
источник
2
Вы должны объяснить немного лучше. Например, куда бы вы поместили этот код?
DevB2F
Ну, я положил его в метод OnCreate (). Каждое добавленное изображение имеет индекс предпочтения по сравнению с ранее добавленными. Я имею в виду, что через индекс 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 .

Винсент Мимун-Прат
источник
RelativeLayout не расширяет frameLayout, вы уверены, что он будет работать?
ekatz
Так и будет. Вы можете использовать любой из FrameLayout или RelativeLayout. У каждого свои способы размещения дочерних представлений. Обратитесь к документации, чтобы узнать больше об этих макетах.
Винсент Мимун-Прат
это путь, чтобы пойти
Альберт Джеймс Тедди
0

Если вы добавляете представление программно, вы можете использовать yourLayout.addView(view, 1);

где 1 is the index.

Александр Маслью
источник
0

Я использую это, если вы хотите, чтобы только один вид выводился на передний план при необходимости:

containerView.bringChildToFront(topView);

containerView - это контейнер видов, которые нужно отсортировать, topView - это вид, который я хочу иметь как самый верхний в контейнере.

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

Милан Юркулак
источник