Placer / superposer (z-index) une vue au-dessus d'une autre vue dans Android


230

J'ai une mise en page linéaire qui se compose d'une vue d'image et d'une vue de texte, l'une en dessous de l'autre dans une mise en page linéaire.

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

Certaines règles peuvent manquer, c'est pour donner une idée de l'apparence de la mise en page. Je veux une autre petite vue texte de disons 50dip de longueur et de largeur, placée sur la vue d'image, par "au-dessus", je voulais dire plus que l'index z que la vue d'image, je veux le placer, au centre et au-dessus (chevauchant) la vue d'image.

Je veux savoir comment placer une vue au-dessus de l'autre, avec un z-index variable (de préférence en disposition linéaire)?

Réponses:


295

Vous ne pouvez pas utiliser un LinearLayout pour cela, mais vous pouvez utiliser un FrameLayout. Dans a FrameLayout, le z-index est défini par l'ordre dans lequel les éléments sont ajoutés, par exemple:

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

Dans ce cas, le TextView serait dessiné au-dessus du ImageView, le long du centre inférieur de l'image.


Oui, je l'ai fait en utilisant la disposition du cadre lui-même après avoir parcouru la documentation. Je vous remercie.
sam

11
Y a-t-il un avantage à utiliser FrameLayout à la place de RelativeLayout pour cela?
Ixx

12
FrameLayout ne se rapporte pas aux autres vues du groupe, il les superpose simplement par rapport au parent. RelativeLayout est plus pour le positionnement par rapport aux autres éléments.
Kevin Coppock

3
Salut kcoppock mon mobile (hdpi) ne respecte pas l'ordre z dans la disposition des cadres, mais j'ai un autre (xhdpi) et respecte cet ordre, savez-vous pourquoi faire cela? Merci d'avance! : D
Merlí Escarpenter Pérez

1
Depuis API 21 / KitKat, vous pouvez désormais utiliser setZ et translationZ; le hack FrameLayout n'est plus nécessaire (enfin!). Cela devrait être la réponse préférée pour le développement moderne 5.0+: stackoverflow.com/a/29703860/358578
pbarranis

183

3
pouvons-nous également l'utiliser dans des fichiers xml?
Annonces

2
Je cherchais quelque chose de tel pour apporter mon point de vue pour changer itz zindex pendant l'animation de traduction.
DeltaCap019

Pourriez-vous trouver une solution pour l'animation de traduction?
nAkhmedov

9
bringChildToFront () change juste l'index de la vue à l'intérieur de son parent
Zar E Ahmer

4
cela
visse

66

RelativeLayout fonctionne de la même manière, la dernière image de la mise en page relative l'emporte.


14
Sauf si vous utilisez l'élévation, vous avez également besoin de la plus grande valeur.
Sami Kuhmonen

5
Cette question a été posée et répondue avant l'élévation. L'utilisation de l'élévation ne résoudra pas le problème si votre application a un minSdk inférieur à Lollipop (sur les téléphones pré-sucettes, la mise en page semblera fausse si vous vous appuyez uniquement sur l'élévation) - vous devez toujours faire attention à l'ordre de la mise en page. Vous avez raison cependant, si vous utilisez l'élévation sur le composant inférieur - vous devez certainement avoir au moins le même ou plus haut sur le dessus.
jt-gilkeson

27

Modification de l'ordre de tirage

Une alternative consiste à modifier l'ordre dans lequel les vues sont dessinées par le parent. Vous pouvez activer cette fonctionnalité à partir de ViewGroup en appelant setChildrenDrawingOrderEnabled (true) et en remplaçant getChildDrawingOrder (int childCount, int i) .

Exemple:

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

Production:

Un appel OrderLayout#setDrawOrder(int)avec 0-1-2 se traduit par:

entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici


Appelez-vous setDrawOrder (i) dans l'activité onCreate ()? Si j'ai 6 widgets dans mon xml, dois-je initialiser chaque ligne de DRAW_ORDERS avec un tableau de 6 chiffres (0-5)?
John Ward

@JohnWard la disposition ci-dessus est uniquement à titre d'exemple, vous pouvez définir votre propre comportement dans getChildDrawingOrder ().
Tobrun

voici un article connexe avec un code beaucoup plus clair: stackoverflow.com/questions/20524162/framelayout-in-reverse
Robert

20

Vous pouvez utiliser à view.setZ(float)partir du niveau de l' API 21. Ici , vous pouvez trouver plus d' informations.


3
Cela devrait maintenant être la réponse préférée pour API 21 / KitKat / 5.0 ou supérieur. L'ancien hack frameLayout n'est heureusement plus nécessaire. Personnellement, je ne comprends pas la différence entre setZ et translationZ, mais ce dernier est un attribut et a très bien fonctionné pour moi. Merci!
pbarranis

Pour les API précédentes, vous pouvez également utiliser ViewCompat # setZ ().
Ali Yucel Akgul

@AliYucelAkgul si vous regardez les documents ici , vous pouvez voir Compatibility: API < 21: No-op . Je pense donc que cela ne fonctionnera pas
Vadim Kotov

@VadimKotov, j'ai essayé dans mon application et ça marche.
Ali Yucel Akgul

@AliYucelAkgul bien, c'est étrange. Peut-être une erreur dans les documents? Êtes-vous sûr à 100% qu'il fonctionne pour l'API <21? J'ai une idée qu'il peut changer l'ordre des vues pour les API précédentes, mais pas de trucs fantaisistes comme l'élévation, etc.
Vadim Kotov

14

J'ai résolu le même problème en ajoutant android:elevation="1dp"à quelle vue vous le voulez par rapport à une autre. Mais il ne peut pas s'afficher en dessous de 5.0, et il y aura un peu d'ombre, si vous pouvez l'accepter, c'est OK.

Donc, la solution la plus correcte qui est @kcoppock a dit.


7

Essayez ceci dans un RelativeLayout:

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

Ça marche pour moi.


2
Vous devriez expliquer un peu mieux. Par exemple, où mettriez-vous ce code?
DevB2F

Eh bien, je l'ai mis dans la méthode OnCreate (). Chaque image ajoutée a un indice de préférence z par rapport à celles ajoutées précédemment. Je veux dire, grâce à l'indice z, je peux changer la position du suivant derrière le précédent.
Rizzo

5

Il existe un moyen d'utiliser LinearLayout. Définissez simplement le marginTop de votre élément précédent sur la valeur négative correspondante et assurez-vous que l'élément que vous voulez en haut se trouve après l'élément que vous souhaitez en dessous dans votre 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 vous ne pouvez pas le faire avec des dispositions linéaires, vous devrez opter pour un RelativeLayout .


RelativeLayout n'étend pas frameLayout, êtes-vous sûr que cela fonctionnera?
ekatz

Ce sera. Vous pouvez utiliser FrameLayout ou RelativeLayout. Chacun ayant différentes manières de placer les vues enfants. Reportez-vous à la documentation pour en savoir plus sur ces dispositions.
Vincent Mimoun-Prat

c'est la voie à suivre
Albert James Teddy

0

Si vous ajoutez la vue par programme, vous pouvez utiliser yourLayout.addView(view, 1);

1 is the index.


0

J'utilise ceci, si vous voulez qu'une seule vue soit mise en avant en cas de besoin:

containerView.bringChildToFront(topView);

containerView est le conteneur de vues à trier, topView est la vue que je veux avoir comme top le plus dans le conteneur.

pour que plusieurs vues soient organisées, il est sur le point d'utiliser setChildrenDrawingOrderEnabled (true) et de remplacer getChildDrawingOrder (int childCount, int i) comme mentionné ci-dessus.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.