Colocación / superposición (índice z) de una vista sobre otra vista en Android


230

Tengo un diseño lineal que consiste en vista de imagen y vista de texto, uno debajo del otro en un diseño lineal.

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

Es posible que falten algunas reglas, esto es para dar una idea de cómo se ve el diseño. Quiero otra pequeña vista de texto de digamos 50dip de largo y ancho, colocada sobre la vista de imagen, por "sobre" quise decir el índice z más que la vista de imagen, quiero colocar esto, en el centro y arriba (superpuesto) la vista de imagen.

Quiero saber cómo podemos colocar una vista sobre la otra, con un índice Z variable (preferiblemente en diseño lineal).

Respuestas:


295

No puede usar un LinearLayout para esto, pero puede usar a FrameLayout. En a FrameLayout, el índice z se define por el orden en que se agregan los elementos, por ejemplo:

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

En este caso, TextView se dibujaría encima de ImageView, a lo largo del centro inferior de la imagen.


Sí, lo hice usando el diseño del marco en sí después de pasar por la documentación. Gracias.
— sáb

11
¿Hay alguna ventaja de usar FrameLayout en lugar de RelativeLayout para esto?
— Ixx

12
FrameLayout no se relaciona con otras vistas en el grupo, solo las superpone con respecto al padre. RelativeLayout es más para posicionamiento en relación con otros elementos.
— Kevin Coppock

3
Hola kcoppock, mi dispositivo móvil (hdpi) no respeta el orden z en el diseño del marco, pero tengo otro (xhdpi) y respeto este orden, ¿sabes por qué hacer esto? ¡Gracias por adelantado! : D
— Merlí Escarpenter Pérez

1
A partir de API 21 / KitKat ahora puede usar setZ y translationZ; el truco FrameLayout ya no es necesario (¡finalmente!). Esta debería ser la respuesta preferida para el desarrollo moderno 5.0+: stackoverflow.com/a/29703860/358578
— pbarranis

183

3
¿podemos usar esto también en archivos xml?
— Anuncios

2
Estaba buscando algo para traer mi punto de vista para cambiar itz zindex durante la animación de traducción.
— DeltaCap019

¿Podría encontrar una solución para la animación de traducción?
— nAkhmedov

99
bringChildToFront () solo cambia el índice de la Vista dentro de su padre
— Zar E Ahmer

44
esto
— daña

66

RelativeLayout funciona de la misma manera, gana la última imagen en el diseño relativo.


14
A menos que use la elevación, entonces también necesita el mayor valor en eso.
— Sami Kuhmonen

55
Esta pregunta fue formulada y respondida antes de que existiera la elevación. El uso de la elevación no solucionará el problema si su aplicación tiene un minSdk menor que Lollipop (en los teléfonos pre-lollipop, el diseño se verá mal si confía solo en la elevación): aún debe prestar atención al orden del diseño. Sin embargo, tiene razón, que si usa la elevación en el componente inferior, definitivamente necesita tener al menos el mismo o más alto en la parte superior.
— jt-gilkeson el

27

Cambiar el orden de sorteo

Una alternativa es cambiar el orden en que las vistas son dibujadas por el padre. Puede habilitar esta función desde ViewGroup llamando a setChildrenDrawingOrderEnabled (verdadero) y anulando getChildDrawingOrder (int childCount, int i) .

Ejemplo:

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

Salida:

Llamar OrderLayout#setDrawOrder(int)con 0-1-2 resulta en:

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí


¿Llamas a setDrawOrder (i) en onCreate () de la actividad? Si tengo 6 widgets en mi xml, ¿necesito inicializar cada fila de DRAW_ORDERS con una matriz de 6 números (0-5)?
— John Ward

@JohnWard el diseño que se muestra arriba es solo para fines de ejemplo, puede definir su propio comportamiento en getChildDrawingOrder ().
— Tobrun

Aquí está la publicación relacionada con mucho código claro: stackoverflow.com/questions/20524162/framelayout-in-reverse
— Robert

20

Puede usar a view.setZ(float)partir del nivel 21 de API. Aquí puede encontrar más información.


3
Esta debería ser la respuesta preferida para API 21 / KitKat / 5.0 o superior. Afortunadamente, el viejo truco frameLayout ya no es necesario. Personalmente, no entiendo la diferencia entre setZ y translationZ, pero este último es un atributo y funcionó muy bien para mí. ¡Gracias!
— pbarranis

Para las API anteriores, también puede usar ViewCompat # setZ ().
— Ali Yucel Akgul

@AliYucelAkgul si miras los documentos aquí , puedes ver Compatibility: API < 21: No-op . Así que creo que no funcionará
— Vadim Kotov

@VadimKotov, lo he intentado en mi aplicación y simplemente funciona.
— Ali Yucel Akgul

@AliYucelAkgul bueno, eso es extraño. Tal vez un error en los documentos? ¿Estás 100% seguro de que funciona para API <21? Tengo una idea de que puede cambiar el orden de las vistas de las API anteriores, pero no hay cosas sofisticadas como la elevación, etc.
— Vadim Kotov

14

Resolví el mismo problema agregando android:elevation="1dp"a qué vista la quieres sobre otra. Pero no puede mostrarse por debajo de 5.0, y tendrá una pequeña sombra, si puede aceptarlo, está bien.

Entonces, la solución más correcta que es @kcoppock, dijo.


7

Pruebe esto en un diseño relativo:

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

Esto funciona para mi.


2
Deberías explicar un poco mejor. Por ejemplo, ¿dónde pondrías este código?
— DevB2F

Bueno, lo puse en el método OnCreate (). Cada imagen agregada tiene un índice z de preferencia sobre las agregadas anteriormente. Quiero decir, a través del índice z puedo cambiar la posición del siguiente detrás del anterior.
— Rizzo

5

Hay una manera de usar LinearLayout. Simplemente configure el marginTop de su elemento anterior en el valor negativo correspondiente y asegúrese de que el elemento que desea en la parte superior esté detrás del elemento que desea en su 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 no puede hacerlo con diseños lineales, tendrá que optar por un diseño relativo .


RelativeLayout no extiende frameLayout, ¿estás seguro de que funcionará?
— ekatz

Va a. Puede usar cualquiera de FrameLayout o RelativeLayout. Cada uno tiene diferentes formas de colocar vistas secundarias. Consulte los documentos para obtener más información sobre esos diseños.
— Vincent Mimoun-Prat

este es el camino a seguir
— Albert James Teddy

0

Si está agregando la Vista mediante programación, puede usar yourLayout.addView(view, 1);

donde 1 is the index.


0

Utilizo esto, si desea que solo se muestre una vista al frente cuando sea necesario:

containerView.bringChildToFront(topView);

containerView es el contenedor de vistas que se ordenarán, topView es la vista que quiero tener como la parte superior del contenedor.

para que se organicen varias vistas, está a punto de usar setChildrenDrawingOrderEnabled (verdadero) y reemplazar getChildDrawingOrder (int childCount, int i) como se mencionó anteriormente.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.