wake-up-neo.net

Verwenden von <include> mit <merge> in ConstraintLayout

Ich habe Probleme beim Verwenden der Tags <include> und <merge> in einem ConstraintLayout. 

Ich möchte eine flache Ansichtshierarchie erstellen (daher Einschränkungen), aber immer noch Elemente haben, die wiederverwendbar sind. Daher verwende ich <include> in meinem Layout und <merge> in den enthaltenen Layouts, um geschachtelte Layouts zu vermeiden (insbesondere das Verschachteln von ConstraintLayouts).

Also habe ich folgendes geschrieben: Übergeordnetes Layout

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

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

Ich erwarte das

 I am expecting this

Stattdessen habe ich das bekommen

 Instead I get this

Die Einschränkungen, die ich in das <include>-Tag einsetze, werden eindeutig durch die Einschränkungen im enthaltenen Layout überschrieben. 

Ist das das erwartete Verhalten? Wenn ja, wie sollen wir mit <include> und ConstraintLayout ein flaches Layout beibehalten?

22
JDenais

Kurze Antwort

Am besten wird <merge>-Block durch eine (verschachtelte) ConstraintLayout ersetzt, anstatt eine redundante Layoutstruktur zu verwenden.




ConstraintLayout ist großartig, aber es funktioniert nicht gut mit der Komposition und Trennung der Verantwortlichkeiten jedes Stücks

Das ist falsch. ConstraintLayout funktioniert gut mit der Wiederverwendung von Layouts. Jedes Layout, in dem alle untergeordneten Ansichten nach Beziehungen zwischen den gleichgeordneten Ansichten und dem übergeordneten Layout angeordnet sind, verhält sich genau so. Dies gilt sogar für RelativeLayout.


Wo ist dann das Problem?

Schauen wir uns genauer an, was <merge> ist.

Der Doc sagt 

Das <merge/>-Tag hilft, redundante Ansichtsgruppen in Ihrer Ansicht zu eliminieren Hierarchie, wenn ein Layout in ein anderes eingefügt wird.

Dies hat den gleichen Effekt wie das Ersetzen des <include>-Elements durch den Inhalt des <merge>-Blocks. Mit anderen Worten, die Ansichten im <merge/>-Block werden ohne Zwischenansichtsgruppe direkt im übergeordneten Layout platziert. Daher werden die Einschränkungen des <include>-Elements vollständig ignoriert.

In diesem speziellen Beispiel werden die Ansichten im einschließenden Layout zweimal als übergeordnetes Element dem übergeordneten Element hinzugefügt.


Fazit

Layout-Ressourcendateien sollen unabhängig voneinander verwendet werden. Um den Begriff "wiederverwendbar" zu qualifizieren, sollte er nicht von seinem übergeordneten Element (der Ansichtsgruppe, in der er zukünftig hinzugefügt wird) abhängig sein. Es würde gut aussehen, wenn Sie das Layout nur einmal einfügen müssten. Aber auch in diesem Fall ist </merge> keine gute Idee, da Sie ihn nicht in einem anderen Layout an einer anderen Position platzieren können.

Offensichtlich haben flache Layout-Hierarchien eine bessere Leistung. Manchmal müssen wir es jedoch opfern.

9
Anees

Android-Dokumentation sagt

Das <merge />-Tag hilft, redundante Ansichtsgruppen in Ihrer Ansicht zu eliminieren Hierarchie, wenn ein Layout in ein anderes eingefügt wird

und hat auch ein Beispiel

Wenn Ihr Hauptlayout eine vertikale LinearLayout ist, in der Zwei aufeinanderfolgende Ansichten können in mehreren Layouts wiederverwendet werden, dann die Das wiederverwendbare Layout, in dem Sie die beiden Ansichten platzieren, erfordert ein eigenes Wurzelansicht. Verwenden Sie jedoch eine andere LinearLayout als Wurzel für die wiederverwendbares Layout würde zu einem vertikalen LinearLayout in einem .__ führen. vertikal LinearLayout. Das verschachtelte LinearLayout hat keinen wirklichen Zweck anders als die UI-Leistung zu verlangsamen.

Siehe auch diese Antwort , wodurch Sie den Merge-Tag besser verstehen können. 

Problem in Ihrem Layout

Für das untergeordnete Layout

Sie setzen Einschränkungen für untergeordnete Elemente im <merge-Tag. Das ist nicht in Ordnung. Weil diese Einschränkungen zur Laufzeit zerstört werden, wenn beide untergeordneten Layouts in Ihrem übergeordneten Layout zusammengeführt werden. (Sie sagen mir, wenn Sie dies ohne Include-Tag tun können, funktionieren Ihre Einschränkungen?)

Für übergeordnetes Layout

Dasselbe gilt für das <include-Tag. Sie geben dem <include-Tag Einschränkungen/benutzerdefinierte Attribute, das verloren geht, da das <merge-Tag mit der Stammansicht verbunden ist. Daher können Sie dem <include keine benutzerdefinierten Attribute mit dem <merge-Tag ..__ zuweisen Die Antwort von Bahman wird funktionieren.

Attribute für <include-Tag funktioniert, wenn sich das Wurzelelement im untergeordneten Layout und kein <merge-Tag befindet. 

Fazit

Da dies klar ist, verwenden Sie <merge und <include nicht wie es sein sollte. Sie haben verstanden, was <include und <merge-Tag tun. Verwenden Sie sie entsprechend.

Wenn Sie nach einer Lösung fragen

ConstraintLayout wurde eingeführt, um komplexes Layout zu lösen. Die Komplexität sollte nicht erhöht werden. Wenn Sie dies mit LinearLayout problemlos tun können, warum sollten Sie Constraints wählen.

Übergeordnetes Layout

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

output

Ich hoffe, ich könnte dich gut verstehen lassen.

3
Khemraj

Als Lösung

Übergeordnetes Layout  enter image description here

<?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 2]

<?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>
2
Artem

include-Tags mit ConstraintLayout-Tags umbrechen und dann die Attribute von include-Tags in diese neuen ConstraintLayout-Tags verschieben:

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

merge ist ein Tag und keine ViewGroup, daher werden alle an das Include übergebenen Parameter ignoriert ... Sie können diese ViewGroup nur mit einem duplizierten Layout zusammenfassen. Wenn Sie sie verwalten möchten, können Sie eine Group erstellen. ... XML-Attribute vom Zusammenführungslayout zu RelativeLayout über inflate

2
Anis BEN NSIR

die Datei view_movie_note.xml sollte einen einzigen XML-Knoten im Stammverzeichnis haben - andernfalls gibt es nicht zwei Layoutknoten, die mit Einschränkungen abgeglichen werden könnten (der Tag <merge> ist möglicherweise unbrauchbar). zwei identische Layouts mit identischer resId zu haben, trägt zum Problem bei, da Einschränkungen immer relativ zu einer resId definiert werden, die hier nicht eindeutig ist.

alternative Ansätze wären a) die Verwendung eines LinearLayout , um zwei Elemente horizontal zu verteilen - oder b) falls es sogar noch mehr untergeordnete Knoten geben sollte (was ich annehmen würde), verwenden Sie CardViews besser in einer GridLayout mit zwei Spalten innerhalb eines GridView / RecyclerView .

eine einzige CardView als Wurzelknoten eines solchen untergeordneten Layouts würde am wenigsten korrekt ausgerichtet werden.

entsprechend dem erwarteten Ergebnis ist eine ConstraintLayout nicht erforderlich, um Knoten gleich auszurichten - mit GridLayoutManager kann man sogar die Spaltenanzahl entsprechend der Anzeigegröße anpassen. Eine StaggeredGridLayoutManager wäre auch eine Option, wenn die Höhe der Elemente variiert.

prinzipiell ist es immer einfacher, mit dem rahmen zu arbeiten, als gegen den rahmen zu arbeiten.

0
Martin Zeitler

Einige Probleme mit Ihrer Frage:

  1. Laut Android-Dokumentation Link

Sie können auch alle Layout-Parameter (alle Attribute von Android: layout_ *) der Root-Ansicht des enthaltenen Layouts überschreiben, indem Sie sie im <include /> -Tag .__ angeben. Alle Einschränkungen, die Sie in das Include-Tag setzen, werden daher entfernt.

  1. Jeder Android:id in include wird NICHT überschrieben, wenn das Merge-Tag in Ihrem enthaltenen Layout verwendet wird. 

  2. Das Verketten und Hinzufügen von Einschränkungen funktioniert bei Ansichten mit unterschiedlichen IDs. Wenn Sie also dieselbe Ansicht mehrmals mit gleichem Gewicht verwenden, funktioniert das nicht über das Include-Tag.

Davon abgesehen, können Sie entweder die gesamte Kopie einfügen 

Daher können Sie Include auf diese Weise nicht verwenden. 

Sie haben 3 Optionen:

  1. Verwenden Sie eine andere ViewGroup (z. B. LinearLayout und dann Constraint-Layout).
  2. Kopieren Sie den Inhalt des include-Layouts mit verschiedenen IDs der Ansichten
  3. Ändern Sie den ConstraintLayout-Code, um Spread-Chains zu unterstützen, sodass das gesamte enthaltene Layout horizontal kopiert wird. 

IMO, 1st Option ist am besten, wenn Sie eine kleine Anzahl dieser Layouts haben. Die zweite Option ist am besten, wenn Sie nur ein Layout haben (in Frage gestellt) und die dritte Option am besten, wenn Sie eine große Anzahl von Layouts haben.

0
Rahul Kumar