Using <include> with <merge> in ConstraintLayout Using <include> with <merge> in ConstraintLayout android android

Using <include> with <merge> in ConstraintLayout


Short answer

The best move will be replacing <merge> block with a (nested) ConstraintLayout rather than using redundant layout structure.




ConstraintLayout is great but it doesn't work well with composition and separation of responsibilities of each piece

That is wrong. ConstraintLayout does work well with reusing layouts. Any layout in which all child views are laid out according to relationships between sibling views and the parent layout, behaves exactly like this. This is true even for RelativeLayout.


Then, where is the problem?

Let's take a closer look at what <merge> is.

The doc says

The <merge/> tag helps eliminate redundant view groups in your view hierarchy when including one layout within another.

It will have the same effect as replacing the <include> element with the contents of <merge> block. In other words, the views in the <merge/> block is directly placed to the parent layout without an intermediate view group. Therefore, the constraints of the <include> element is completely ignored.

In this particular example, the views in the including layout is added two times to the parent as the second one on top of another.


Conclusion

Layout resource files are intended to be used independently. To qualify the term reusable, it should not depend on it's parent (The view group in which it will be added in future). It would be looking okay if you had to include the layout only one time. But </merge> won't be a good idea in that case too because you can't place it in any different layout in a different position.

Obviously, flat layout hierarchies have better performance. However, sometimes we may have to sacrifice it.


Android documentation says

The <merge /> tag helps eliminate redundant view groups in your view hierarchy when including one layout within another

and has an example too

If your main layout is a vertical LinearLayout in which two consecutive views can be re-used in multiple layouts, then the re-usable layout in which you place the two views requires its own root view. However, using another LinearLayout as the root for the re-usable layout would result in a vertical LinearLayout inside a vertical LinearLayout. The nested LinearLayout serves no real purpose other than to slow down your UI performance.

Also see this answer, which will make you understand merge tag more.

Problem in your layout

For the child layout

You put constraints on child elements inside <merge tag. That's not okay. Because that constraints are destroyed at run time when both child layout are merged inside your parent layout. (You tell me if you can do this without include tag, will your constraints work?)

For parent layout

Same for <include tag, you are giving constraints/custom attributes to <include tag, that will be lost, because <merge tag is joined to the root view, so you can not apply custom attributes to the <include with <merge tag.That's why Bahman answer will work.

Attributes on <include tag works when you have root element inside child layout and no <merge tag.

Conclusion

As this is clear, you are not using <merge and <include, as it should be. You have understand what <include and <merge tag do. So use them appropriately.

If you ask solution

ConstraintLayout was introduced to solve complex layout. Not to increase complexity. So when you can do this easily with LinearLayout why to choose Constraints.

Parent 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

I hope I could make you understand well.


Wrap include tags with ConstraintLayout tags then move attributes of include tags to these new ConstraintLayout tags:

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