在ConstraintLayout中使用<include>和<merge>

JDe*_*ais 28 android android-layout viewgroup android-constraintlayout

我在使用标签<include>和<merge>ConstraintLayout内部时遇到问题.

我想创建一个平面视图层次结构(因此Constraints),但仍然有可重用的元素.所以我<include>在我的布局和<merge>包含的布局中使用以避免嵌套布局(特别是避免嵌套的ConstraintLayouts)

所以我写了这样的:父布局

<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>
Run Code Online (Sandbox Code Playgroud)

这个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>
Run Code Online (Sandbox Code Playgroud)

我期待着这一点

我期待着这一点

相反,我得到了这个

相反,我得到了这个

很明显,我在<include>标签中放置的约束被包含的布局中的约束覆盖.

这是预期的行为吗?如果是的话,我们应该如何使用<include>和ConstraintLayout 保持平面布局?

Ber*_*yle 23

简短的回答

最好的举措是用<merge>(嵌套)替换块ConstraintLayout而不是使用冗余布局结构.




ConstraintLayout非常棒,但它不适用于每件作品的构图和分离

那是错的.ConstraintLayout重复使用布局确实很好.根据兄弟视图和父布局之间的关系布局所有子视图的任何布局都与此完全相同.即便如此也是如此RelativeLayout.


那么,问题出在哪里?

让我们仔细看看是什么<merge>.

医生说

<merge/>在一个布局中包含一个布局时,该标记有助于消除视图层次结构中的冗余视图组.

它<include>与使用<merge>块的内容替换元素具有相同的效果.换句话说,<merge/>块中的视图直接放置到父布局而没有中间视图组.因此,<include>完全忽略了元素的约束.

在此特定示例中,包含布局中的视图将两次添加到父级,而第二次添加到另一个之上.


结论

布局资源文件旨在独立使用.要限定可重用的术语,它不应该依赖于它的父级(将来将添加它的视图组).如果你只需要包含一次布局,那就好了.但</merge>在这种情况下也不是一个好主意,因为你不能将它放在不同位置的任何不同布局中.

显然,平面布局层次结构具有更好的性能.但是,有时我们可能不得不牺牲它.

  • 好的答案与解释权衡的结论/讨论完全相关,这让读者对他们选择在帖子中应用技巧有信心。 (2认同)

Khe*_*raj 6

Android 文档说

<merge />当在另一个布局中包含一个布局时,该标记有助于消除视图层次结构中的冗余视图组

还有一个例子

如果您的主布局是垂直布局LinearLayout,其中两个连续的视图可以在多个布局中重用,那么放置两个视图的可重用布局需要自己的根视图。但是,使用另一个LinearLayout作为可重用布局的根将导致垂直LinearLayout内部的垂直LinearLayout。LinearLayout除了降低 UI 性能外,嵌套没有任何实际用途。

另请参阅此答案,这将使您更了解合并标签。

你的布局有问题

对于子布局

您对<merge标签内的子元素施加约束。那不行。因为当两个子布局合并到父布局中时,约束会在运行时被破坏。(你告诉我如果你可以在没有包含标签的情况下做到这一点,你的约束会起作用吗?)

对于父布局

对于<include标记,您正在为标记提供约束/自定义属性<include,这将丢失,因为<merge标记已加入根视图,因此您无法将自定义属性应用于<includewith<merge标记。这就是为什么Bahman 的答案会起作用。

<include当您在子布局中有根元素且没有<merge标签时,标签上的属性有效。

结论

很明显,您没有使用<mergeand <include,因为它应该是。你必须了解<include和<merge标签做。所以要适当地使用它们。

如果你问解决方案

引入ConstraintLayout来解决复杂的布局。不是为了增加复杂性。所以当你可以轻松地做到这一点时,LinearLayout为什么要选择Constraints。

父布局

<?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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

输出

我希望我能让你很好地理解。