Espacement régulier des vues à l'aide de ConstraintLayout

Réponses:

323

Il existe deux façons d'accomplir cela en utilisant ConstraintLayout: Chaînes et Lignes directrices . Pour utiliser Chaînes, assurez-vous d'utiliser la ConstraintLayoutversion bêta 3 ou une version plus récente et si vous souhaitez utiliser l'éditeur de mise en page visuelle dans Android Studio, assurez-vous que vous utilisez Android Studio 2.3 Bêta 1 ou une version plus récente.

Méthode 1 - Utilisation de chaînes

Ouvrez l'éditeur de mise en page et ajoutez vos widgets comme d'habitude, en ajoutant des contraintes parentales si nécessaire. Dans ce cas, j'ai ajouté deux boutons avec des contraintes en bas du parent et sur le côté du parent (côté gauche pour le bouton Enregistrer et côté droit pour le bouton Partager):

entrez la description de l'image ici

Notez que dans cet état, si je passe en mode paysage, les vues ne remplissent pas le parent mais sont ancrées aux coins:

entrez la description de l'image ici

Mettez en surbrillance les deux vues, soit en cliquant Ctrl / Cmd, soit en faisant glisser une boîte autour des vues:

entrez la description de l'image ici

Ensuite, faites un clic droit sur les vues et choisissez "Centrer horizontalement":

entrez la description de l'image ici

Cela met en place une connexion bidirectionnelle entre les vues (c'est ainsi qu'une chaîne est définie). Par défaut, le style de chaîne est "spread", qui est appliqué même si aucun attribut XML n'est inclus. En respectant ce style de chaîne, mais en définissant la largeur de nos vues pour permettre 0dpaux vues de remplir l'espace disponible, en se répartissant uniformément sur le parent:

entrez la description de l'image ici

Ceci est plus visible en vue paysage:

entrez la description de l'image ici

Si vous préférez ignorer l'éditeur de mise en page, le XML résultant ressemblera à:

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
    android:id="@+id/button_save"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="@string/button_save_text"
    android:layout_marginStart="8dp"
    android:layout_marginBottom="8dp"
    android:layout_marginEnd="4dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/button_share"
    app:layout_constraintHorizontal_chainStyle="spread" />

<Button
    android:id="@+id/button_share"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="@string/button_share_text"
    android:layout_marginStart="4dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    app:layout_constraintLeft_toRightOf="@+id/button_save"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintBottom_toBottomOf="parent" />

</android.support.constraint.ConstraintLayout>

Détails:

  • définir la largeur de chaque élément sur 0dpou MATCH_CONSTRAINTlaisser les vues remplir le parent (facultatif)
  • les vues doivent être liées entre elles de manière bidirectionnelle (à droite des liens du bouton d'enregistrement vers le bouton de partage, à gauche des liens du bouton de partage vers le bouton d'enregistrement), cela se fera automatiquement via l'éditeur de mise en page lorsque vous choisissez "Centrer horizontalement"
  • la première vue de la chaîne peut spécifier le style de chaîne via layout_constraintHorizontal_chainStyle, voir la documentation des différents styles de chaîne, si le style de chaîne est omis, la valeur par défaut est "propagation"
  • le poids de la chaîne peut être réglé via layout_constraintHorizontal_weight
  • cet exemple est pour une chaîne horizontale, il existe des attributs correspondants pour les chaînes verticales

Méthode 2 - Utilisation d'une ligne directrice

Ouvrez votre mise en page dans l'éditeur et cliquez sur le bouton guide:

entrez la description de l'image ici

Sélectionnez ensuite "Ajouter une ligne de guidage verticale": entrez la description de l'image ici

Une nouvelle ligne directrice apparaîtra, qui par défaut, sera probablement ancrée à gauche dans des valeurs relatives (indiquées par une flèche orientée vers la gauche):

guide relatif de l'éditeur de mise en page

Cliquez sur la flèche orientée vers la gauche pour la faire passer à une valeur de pourcentage, puis faites glisser la ligne de guidage vers la marque 50%:

guide de pourcentage de l'éditeur de mise en page

La ligne directrice peut maintenant être utilisée comme point d'ancrage pour d'autres vues. Dans mon exemple, j'ai attaché la droite du bouton Enregistrer et la gauche du bouton Partager à la ligne directrice:

mise en page finale

Si vous souhaitez que les vues remplissent l'espace disponible, la contrainte doit être définie sur "Toute taille" (les lignes ondulées s'étendant horizontalement):

toute contrainte de taille

(C'est la même chose que de régler layout_widthsur 0dp).

Une directive peut également être créée en XML assez facilement plutôt que d'utiliser l'éditeur de mise en page:

<android.support.constraint.Guideline
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/guideline"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.5" />
AdamK
la source
1
Je n'ai pas pu trouver un moyen de créer une ligne directrice avec une contrainte. Je veux qu'une ligne directrice horizontale soit au milieu de deux vues. Imaginez une vue plus grande avec une hauteur de 100dp en haut et une plus petite avec une hauteur de 50dp en bas. Je veux placer une ligne directrice au milieu de l'espace entre eux.
headsvk
3
Je ne pense pas que vous puissiez ajouter des contraintes à la directive elle-même. Vous pouvez ajouter plusieurs directives, puis contraindre les vues à ces directives. Vous voudrez peut-être publier une nouvelle question avec des détails sur ce que vous essayez d'accomplir. N'hésitez pas à le coller ici également.
AdamK
Merci, cher monsieur. C'était une aide opportune et efficace.
iSofia le
Je veux donner une largeur proportionnelle aux vues. Par exemple, je veux que le bouton de partage ait deux fois la largeur du bouton de sauvegarde. Sans utiliser de lignes directrices car mes vues ne sont pas positionnées les unes à côté des autres comme dans cet exemple. c'est possible?
Shubham Naik
Vous devez convertir les valeurs données par les lignes directrices en marges ou en rembourrages réels. Les directives fonctionnent uniquement en mode conception.
Abhinav Saxena
49

Pour créer 2 vues sur la même ligne, de largeur égale, il suffit de définir

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <Button
        android:id="@+id/button1"
        android:layout_width="0dp"  
        android:layout_height="wrap_content"
        android:text="Button 1"
        app:layout_constraintEnd_toStartOf="@+id/button2"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button1" />

</android.support.constraint.ConstraintLayout>

Remarque

  • largeur = 0dp ( MATCH_CONSTRAINT)
  • Contrainte button1et button2doit aimer ci-dessus

Résultat

PLUS
Si vous voulez View1plus grand que View2vous pouvez utiliser weightou percent.
Exemple, View1width = 2 * View2width use weight

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <Button
        android:id="@+id/button3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 3"
        app:layout_constraintEnd_toStartOf="@+id/button4"
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintStart_toStartOf="parent"
        />

    <Button
        android:id="@+id/button4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@+id/button3"
        />

</android.support.constraint.ConstraintLayout>

Résultat

Exemple, View1width = 2 * View2width use percent

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <Button
        android:id="@+id/button5"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 5"
        app:layout_constraintEnd_toStartOf="@+id/button6"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintWidth_percent="0.667"
        />

    <Button
        android:id="@+id/button6"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 6"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button5"
        app:layout_constraintWidth_percent="0.333"
        />

</android.support.constraint.ConstraintLayout>

Résultat

Phan Van Linh
la source
23

Eh bien si ça aide quelqu'un

la clé est ici app:layout_constraintHorizontal_weight="1"et
la meilleure chose à propos de la disposition des contraintes est qu'elle prend en charge la dépendance circulaire et voici ce que j'ai fait en utilisant exactement cela.

Pour le premier enfant
app:layout_constraintEnd_toStartOf="@+id/textInputSecondChild"

Pour le deuxième enfant

app:layout_constraintLeft_toRightOf="@+id/textInputFirstChild"

voici la démo complète

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInputParent"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent">

    <EditText
        android:id="@+id/editTextParent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/state" />
</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInputFirstChild"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintEnd_toStartOf="@+id/textInputSecondChild"
    app:layout_constraintHorizontal_weight="1"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textInputParent">

    <EditText
        android:id="@+id/editTextChildOne"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/pin_code" />
</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInputSecondChild"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintHorizontal_weight="1"
    app:layout_constraintLeft_toRightOf="@+id/textInputFirstChild"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textInputParent">

    <EditText
        android:id="@+id/editTextChildSecond"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/country" />
</android.support.design.widget.TextInputLayout>
recrueDéveloppeur
la source
9

Vous devriez lire sur les chaînes pondérées. Un exemple de code est ici.

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <TextView
        android:id="@+id/figure_1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintEnd_toStartOf="@id/figure_2"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toStartOf="parent"
        tools:text="1"
        />

    <TextView
        android:id="@+id/figure_2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintEnd_toStartOf="@id/figure_3"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/figure_1"
        tools:text="2"
        />

    <TextView
        android:id="@+id/figure_3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintEnd_toStartOf="@id/figure_4"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/figure_2"
        tools:text="3"
        />

    <TextView
        android:id="@+id/figure_4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/figure_3"
        tools:text="4"
        />
</android.support.constraint.ConstraintLayout>

Alors, ensemble android:layout_width="0dp", app:layout_constraintHorizontal_weight="1"et lier toutes les vues avec les voisins comme:

app:layout_constraintStart_toEndOf="@id/figure_2"
app:layout_constraintEnd_toStartOf="@id/figure_4"

entrez la description de l'image ici

CoolMind
la source
à quoi sert d'afficher une réponse de plus exactement comme une autre, publiée il y a deux ans?
@Subzero, j'ai vu plusieurs fois des réponses égales avec un taux élevé. Même les lignes de code étaient les mêmes. Je soupçonne que certains auteurs ont copié le mien et ont même eu plus d'avantages. Dans ce cas, les réponses sont différentes, j'ai également utilisé d'autres sources pour comprendre comment les pondérations fonctionnent ConstraintLayout, et seule la première réponse n'était pas suffisante pour obtenir une image ci-dessus.
CoolMind
3

Une fois que vous avez vos éléments enchaînés, vous pouvez toujours utiliser des poids sur eux comme une disposition relative pour les garder uniformément espacés. L'exemple ci-dessous montre comment les garder régulièrement espacés avec des textViews de taille différente.

<TextView1
     app:layout_constraintHorizontal_weight="1" />
 <TextView2
     app:layout_constraintHorizontal_weight="1" />
 <TextView3
     app:layout_constraintHorizontal_weight="1" />
 <TextView4
     app:layout_constraintHorizontal_weight="1" />

entrez la description de l'image ici

tzg
la source