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.