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

se sentó
fuente

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.

Kevin Coppock
fuente
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

Intenta .bringToFront():

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

diyism
fuente
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.

jt-gilkeson
fuente
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í

Tobrun
fuente
¿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.

Vadim Kotov
fuente
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.

treinta yuanes
fuente
7

Pruebe esto en un diseño relativo:

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

Esto funciona para mi.

Rizzo
fuente
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>
Tim
fuente
4

AFAIK no puede hacerlo con diseños lineales, tendrá que optar por un diseño relativo .

Vincent Mimoun-Prat
fuente
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.

Alexander Maslew
fuente
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.

Milan Jurkulak
fuente