Je ne parviens pas à utiliser les balises <include>
et <merge>
à l'intérieur d'un objet ConstraintLayout.
Je souhaite créer une hiérarchie de vues à plat (donc des contraintes), tout en conservant des éléments réutilisables. J'utilise donc <include>
dans ma mise en page et <merge>
dans les mises en page incluses pour éviter d'avoir des mises en page imbriquées (en particulier pour éviter l'imbrication de ConstraintLayouts)
J'ai donc écrit ceci:
<Android.support.constraint.ConstraintLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<include
Android:id="@+id/review_1"
layout="@layout/view_movie_note"
Android:layout_width="0dp"
Android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/review_2"/>
<include
layout="@layout/view_movie_note"
Android:id="@+id/review_2"
Android:layout_width="0dp"
Android:layout_height="0dp"
Android:layout_marginLeft="7dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/review_1"
app:layout_constraintRight_toRightOf="parent"
/>
</Android.support.constraint.ConstraintLayout>
et cette view_movie_note:
<merge>
<TextView
Android:id="@+id/note_Origin"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginBottom="15dp"
Android:layout_marginStart="5dp"
app:layout_constraintStart_toStartOf="@+id/cardView2"
app:layout_constraintTop_toTopOf="parent"
Android:layout_marginLeft="5dp" />
<Android.support.v7.widget.CardView
Android:id="@+id/five_star_view_container"
Android:layout_width="0dp"
Android:layout_height="52dp"
Android:layout_marginBottom="8dp"
Android:layout_marginTop="10dp"
Android:elevation="3dp"
app:cardUseCompatPadding="true"
app:contentPaddingTop="22dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_min="52dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/note_Origin">
<FiveStarsView
Android:id="@+id/five_star_view"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center_horizontal" />
</Android.support.v7.widget.CardView>
<Android.support.v7.widget.CardView
Android:id="@+id/cardView2"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginTop="20dp"
app:cardBackgroundColor="@color/colorPrimary"
app:contentPaddingLeft="15dp"
app:contentPaddingRight="15dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/note_Origin">
<TextView
Android:id="@+id/grade"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:textSize="12sp" />
</Android.support.v7.widget.CardView>
</merge>
Je m'attends à cela
Au lieu de cela, j'ai ce
Il est clair que les contraintes que je mets dans la balise <include>
sont remplacées par les contraintes de la disposition incluse.
Est-ce le comportement attendu? Si oui, comment devons-nous conserver une mise en page plate en utilisant <include>
et ConstraintLayout?
_ {Le meilleur choix sera de remplacer le bloc <merge>
par une (variable) ConstraintLayout
plutôt que d'utiliser une structure de présentation redondante.
ConstraintLayout est génial mais il ne fonctionne pas bien avec la composition et séparation des responsabilités de chaque pièce
C'est faux. ConstraintLayout
fonctionne bien avec la réutilisation de présentations. Toute disposition dans laquelle toutes les vues enfants sont disposées en fonction des relations entre les vues frères et la disposition parente se comporte exactement comme ceci. Cela est vrai même pour RelativeLayout
.
Regardons de plus près ce que <merge>
est.
Le doc dit
La balise
<merge/>
permet d’éliminer les groupes de vues redondants dans votre vue hiérarchie lors de l’inclusion d’une mise en page dans une autre.
Cela aura le même effet que de remplacer l'élément <include>
par le contenu du bloc <merge>
. En d'autres termes, les vues du bloc <merge/>
sont directement placées dans la disposition parente sans groupe de vues intermédiaire. Par conséquent, les contraintes de l'élément <include>
sont complètement ignorées.
Dans cet exemple particulier, les vues de la disposition y compris sont ajoutées deux fois au parent en tant que deuxième au-dessus d'une autre.
Les fichiers de ressources de mise en page sont destinés à être utilisés indépendamment. Pour qualifier le terme réutilisable, il ne devrait pas dépendre de son parent (groupe de vues dans lequel il sera ajouté à l'avenir). Si vous ne deviez inclure la mise en page qu’une seule fois, cela vous irait. Mais </merge>
ne sera pas une bonne idée dans ce cas aussi, car vous ne pouvez pas le placer dans une mise en page différente à une position différente.
De toute évidence, les hiérarchies de mise en page à plat offrent de meilleures performances. Cependant, nous pouvons parfois devoir le sacrifier.
La balise
<merge />
permet d’éliminer les groupes de vues redondants dans votre vue hiérarchie lors de l'inclusion d'une mise en page dans une autre
et a aussi un exemple
Si votre mise en page principale est une verticale
LinearLayout
dans laquelle Deux vues consécutives peuvent être réutilisées dans plusieurs mises en page, puis le La mise en page réutilisable dans laquelle vous placez les deux vues nécessite sa propre vue racine. Cependant, utilisez un autreLinearLayout
comme racine du fichier une disposition réutilisable entraînerait unLinearLayout
vertical dans un verticalLinearLayout
.LinearLayout
imbriqué ne sert à rien autre que de ralentir les performances de votre interface utilisateur.
Voir aussi cette réponse , qui vous permettra de mieux comprendre la balise de fusion.
Pour la mise en page enfant
Vous mettez des contraintes sur les éléments enfants à l'intérieur de la balise <merge
. Ça ne va pas. Parce que ces contraintes sont détruites au moment de l'exécution lorsque les deux modèles enfants sont fusionnés dans votre modèle parent. (Vous me dites si vous pouvez le faire sans inclure la balise include, vos contraintes fonctionneront-elles?)
Pour la mise en page parent
Pareil pour la balise <include
, vous attribuez des contraintes/attributs personnalisés à la balise <include
, qui sera perdue, car la balise <merge
est jointe à la vue racine. Vous ne pouvez donc pas appliquer d'attributs personnalisés à la balise <include
avec <merge
. C'est pourquoi Bahman réponse fonctionnera.
Les attributs sur la balise <include
fonctionnent lorsque vous avez un élément racine dans la présentation enfant et la balise no <merge
.
Comme cela est clair, vous n'utilisez pas <merge
et <include
, comme il se doit. Vous avez compris ce que font les balises <include
et <merge
. Alors utilisez-les à bon escient.
ConstraintLayout a été introduit pour résoudre une mise en page complexe. Ne pas augmenter la complexité. Alors, quand vous pouvez le faire facilement avec LinearLayout
, pourquoi choisir Constraints
.
Disposition des parents
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
>
<include
Android:id="@+id/review_1"
layout="@layout/view_movie_note"
Android:layout_width="0dp"
Android:layout_height="wrap_content"
Android:layout_weight="1"
/>
<include
Android:id="@+id/review_2"
layout="@layout/view_movie_note"
Android:layout_width="0dp"
Android:layout_height="wrap_content"
Android:layout_marginLeft="7dp"
Android:layout_weight="1"
/>
</LinearLayout>
view_movie_note.xml
<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="wrap_content"
Android:layout_height="wrap_content">
<TextView
.../>
<Android.support.v7.widget.CardView
...
</Android.support.v7.widget.CardView>
<Android.support.v7.widget.CardView
...
</Android.support.v7.widget.CardView>
</Android.support.constraint.ConstraintLayout>
J'espère que je pourrais vous faire bien comprendre.
Comme solution
<?xml version="1.0" encoding="utf-8"?>
<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">
<Android.support.v7.widget.LinearLayoutCompat
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:weightSum="2">
<include
Android:id="@+id/review_1"
layout="@layout/view_movie_note"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_weight="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/review_2"
app:layout_constraintTop_toTopOf="parent" />
<include
Android:id="@+id/review_2"
layout="@layout/view_movie_note"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginLeft="7dp"
Android:layout_weight="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/review_1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</Android.support.v7.widget.LinearLayoutCompat>
</Android.support.constraint.ConstraintLayout>
view_movie_note
<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content">
<TextView
Android:id="@+id/note_Origin"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginBottom="15dp"
Android:layout_marginLeft="5dp"
Android:layout_marginStart="5dp"
app:layout_constraintStart_toStartOf="@+id/cardView2"
app:layout_constraintTop_toTopOf="parent" />
<Android.support.v7.widget.CardView
Android:id="@+id/five_star_view_container"
Android:layout_width="wrap_content"
Android:layout_height="52dp"
Android:layout_marginBottom="8dp"
Android:layout_marginTop="10dp"
Android:elevation="3dp"
app:cardUseCompatPadding="true"
app:contentPaddingTop="22dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_min="52dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/note_Origin">
<!--<FiveStarsView-->
<!--Android:id="@+id/five_star_view"-->
<!--Android:layout_width="wrap_content"-->
<!--Android:layout_height="wrap_content"-->
<!--Android:layout_gravity="center_horizontal" />-->
<RatingBar
Android:id="@+id/ratingBar"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content" />
</Android.support.v7.widget.CardView>
<Android.support.v7.widget.CardView
Android:id="@+id/cardView2"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginTop="20dp"
app:cardBackgroundColor="@color/colorPrimary"
app:contentPaddingLeft="15dp"
app:contentPaddingRight="15dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/note_Origin">
<TextView
Android:id="@+id/grade"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:textSize="12sp" />
</Android.support.v7.widget.CardView>
</Android.support.constraint.ConstraintLayout>
Enveloppez les balises include
avec les balises ConstraintLayout
, puis déplacez les attributs des balises include
vers ces nouvelles balises ConstraintLayout
:
<Android.support.constraint.ConstraintLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.constraint.ConstraintLayout
Android:id="@+id/review_1"
Android:layout_width="0dp"
Android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/review_2">
<include layout="@layout/view_movie_note" />
</Android.support.constraint.ConstraintLayout>
<Android.support.constraint.ConstraintLayout
Android:id="@+id/review_2"
Android:layout_width="0dp"
Android:layout_height="0dp"
Android:layout_marginLeft="7dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/review_1"
app:layout_constraintRight_toRightOf="parent">
<include layout="@layout/view_movie_note" />
</Android.support.constraint.ConstraintLayout>
</Android.support.constraint.ConstraintLayout>
la fusion est une balise et non un ViewGroup. Ainsi, tout le paramètre transmis à l'include sera ignoré ... Vous pouvez définir ce ViewGroup uniquement avec une présentation dupliquée. Si vous avez besoin de la gérer, vous pouvez créer un Group . ... Attributs XML de la disposition de fusion à RelativeLayout via inflate
le fichier view_movie_note.xml
doit avoir un seul nœud xml à la racine - sinon, il n'y aura pas deux nœuds de présentation pouvant être alignés sur des contraintes (la balise <merge>
peut être inutile). Le fait d'avoir deux présentations identiques avec resId
identique ajoute au problème, car les contraintes sont toujours définies par rapport à une resId
, ce qui n'est pas unique ici.
des approches alternatives seraient, a) d'utiliser un LinearLayout afin de distribuer deux éléments horizontalement - ou b) au cas où il y aurait même quelques nœuds enfants (que je supposerais), il serait préférable d'utiliser CardView
s dans un GridLayout
avec deux colonnes, dans un GridView / RecyclerView .
un seul CardView
en tant que nœud racine d'une telle disposition enfant serait le moins à aligner correctement.
selon le résultat attendu, il n'est pas nécessaire d'utiliser une ConstraintLayout
pour aligner les nœuds de la même manière. Avec la variable GridLayoutManager
, vous pouvez même ajuster le nombre de colonnes en fonction de la taille d'affichage. Une StaggeredGridLayoutManager
serait également une option lorsque la hauteur des éléments varie.
en principe, il est toujours plus facile de travailler avec le cadre que de travailler contre le cadre.
Quelques problèmes avec votre question:
Vous pouvez également remplacer tous les paramètres de présentation (tous les attributs Android: layout_ *) de la vue racine de la présentation incluse en les spécifiant dans la balise <include /> Ainsi, toute contrainte que vous avez mise dans la balise include sera supprimée.
Tout Android:id
dans l'inclusion NE sera PAS remplacé si la balise de fusion est utilisée dans votre mise en page incluse.
Le chaînage et l'ajout de contraintes fonctionnent sur des vues ayant différents identifiants. Donc, pour inclure la même vue plusieurs fois avec le même poids ne fonctionnera pas avec la balise include.
Cela étant dit, vous pouvez soit copier coller tout le
Par conséquent, vous ne pouvez pas utiliser include de cette manière.
Il ne vous reste que 3 options:
include
avec différents identifiants de vuesConstraintLayout
pour prendre en charge les chaînes de répartition de sorte que la présentation incluse entière soit copiée horizontalement. IMO, la 1ère option est préférable si vous avez un petit nombre de ces mises en page, la 2ème option est la meilleure si vous n'avez qu'une seule mise en page (posée en question) et la 3ème option est la meilleure si vous avez un grand nombre de mises en page.