How do margins in chains work in ConstraintLayout 1.1.0 (beta)

柔情痞子 提交于 2019-12-04 01:54:29

I can find no documentation that gives an authoritative answer to this exact question. However, there is a little bit of discussion about margins in the API documentation for ConstraintLayout:

If side margins are set, they will be applied to the corresponding constraints (if they exist)

In the specific instance of a chain, you have two-way constraints between each view. That is, not only is View A's end constrained to View B's start, but View B's start is also constrained to View A's end.

In your posted layout, View A has an end constraint and an end margin, but View B has a start constraint with no start margin. As far as I can tell, this means you have conflicting rules in your layout (View A wants to be 8dp away from View B, but View B wants to be 0dp from View A). Perhaps different versions of the ConstraintLayout library have different strategies for (a) determining whether this even counts as a conflict and (b) resolving the conflict if so.

Via experimentation, here is how I've found margins to work in chains on different ConstraintLayout library versions:

Version 1.0.2

Side margins on each view in the chain don't depend on or affect other views in the chain. This has (at least) two visible effects on behavior. First, adding margin to one view will push the other view away by that amount, regardless of that view's margins. Second, adding margin to one view will not affect margins of views farther down the chain (e.g. putting 8dp end margin on your first view does not by itself also cause 8dp worth of space to appear between your second and third views).

Version 1.1.0-beta4

Side margins on each view in the chain both depend on and affect other views in the chain. Again, this has two visible effects on behavior. First, adding margin to one view will not push the other view away unless it also has a margin of that same amount*. Second, adding margin between the first and second view of the chain will also affect the spacing between the second and third view of the chain**.

*: It seems that 1.1.0-beta4 allows just a start margin to push the views apart, while just an end margin will have no effect. Regardless, I recommend matching the margins.

**: I suspect this is because the chain is trying to allocate "space" evenly. The margins between views A and B create a gap, and since the chain wants to enforce a consistent spacing it adds a similar gap between views B and C.

Examples:

Stripped way down, here's a layout just like your original, with the margins changed slightly. I've left every other attribute unchanged.

<android.support.constraint.ConstraintLayout>

    <TextView
        android:layout_marginEnd="8dp"/>

    <TextView
        android:layout_marginStart="8dp"/>

    <TextView/>

</android.support.constraint.ConstraintLayout>

v1.0.2:

v1.1.0-beta4:

This should illustrate the two differences between the library versions. Again, I've been completely unable to find official documentation that explains all this, but it appears to be true just based on experimentation.

Expanding on Ben P.'s answer, I have determined the following regarding margins in ConstraintLayout chains. This information applies to ConstraintLayout version 1.1.0-beta4.

General Observations

  1. Within a chain, all start margins (android:layout_marginStart) are honored. This means that the spacing between the views will not be less than the specified start margin. However, the spacing may be greater as explained below.

  2. End margins (android:layout_marginEnd) have no relevance and seem to be ignored. This does not apply to the end margins of the view at the end of the chain but only to the interior margins where views are cross-linked to create the chain.

  3. When a chain is centered within its constraints, the chain is centered between the start margin of the chain's head and the end margin of the chain's tail.

In the examples below, views "A","D" ang "G" are constrained to the parent start. Views "C", "F" and "I" are constrained to the parent end.

Chain Style: packed

If the chain style is "packed," all views are placed end-to-end separated by the specified start margins. The spacing between the views can vary according to how the start margins are defined. In the following image, the width of the views are match_constraints and the margins are set as indicated.

If the widths of the views are set to something other than match_constraints, the views are still packed with the specified margins but the chain is centered between the start margin of the chain's head and the end margin of the chain's tail.

I came to this interpretation instead of considering the end margin to be attached to the end view because the Android Studio designer has this same interpretation:

Chain Style: spread

In the "spread" chain style, all views are distributed between the start and end constraints such that the space before and after each view is the same and equal to the greatest start margin defined. If the width of each view is match_constraints, then all the views will have the same width by default.

Chain Style: spread_inside

The spread_inside style of chains will take the first view of the chain and anchor it to its start constraint while honoring its start margin. The end view will be anchored to its end constraint while honoring its end margin. Interior views will be distributed with equal spacing between the views like spread chains.


Below is the same layout with various margins set. Views "F" and "I" have a start margin of 8dp set but the gap has expanded to 16dp. View "G", "H" and "I" are all of equal width although they don't appear to be.

The XML for this layout is presented at the end of this post.

Of interest but of no real importance: The different chain types are indistinguishable if the views have a width of match_constraints and all margins are zero.

The information above also applies to vertical chains. Substitute android:layout_marginTop for android:layout_marginStart and android:layout_marginBottom for android:layout_marginEnd.

Layout

<android.support.constraint.ConstraintLayout 
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_blue_light">

    <TextView
        android:id="@+id/heading1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="packed, match_constraints"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:textSize="16sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/textA"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginTop="8dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="A"
        android:textColor="@android:color/black"
        app:layout_constraintEnd_toStartOf="@+id/textB"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/heading1"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:background="#ff00cc"
        app:layout_constraintEnd_toStartOf="@id/textB"
        app:layout_constraintTop_toTopOf="@id/textB" />

    <TextView
        android:id="@+id/textB"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginStart="8dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="B"
        android:textColor="@android:color/white"
        app:layout_constraintEnd_toStartOf="@+id/textC"
        app:layout_constraintStart_toEndOf="@+id/textA"
        app:layout_constraintTop_toTopOf="@+id/textA"
        tools:ignore="HardcodedText" />

    <View
        android:id="@+id/view16dpOnC"
        android:layout_width="16dp"
        android:layout_height="35dp"
        android:background="#fffb00"
        app:layout_constraintEnd_toStartOf="@id/textC"
        app:layout_constraintTop_toTopOf="@+id/textC" />

    <TextView
        android:id="@+id/textC"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginStart="16dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="C"
        android:textColor="@android:color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textB"
        app:layout_constraintTop_toTopOf="@+id/textA"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/heading2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="spread, match_constraints"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:textSize="16sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textA"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="16dp"
        android:layout_height="35dp"
        android:background="#00ff19"
        app:layout_constraintEnd_toStartOf="@id/textD"
        app:layout_constraintTop_toTopOf="@id/textD" />

    <TextView
        android:id="@+id/textD"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginTop="8dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="D"
        android:textColor="@android:color/black"
        app:layout_constraintEnd_toStartOf="@+id/textE"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/heading2"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="16dp"
        android:layout_height="35dp"
        android:background="#fffb00"
        app:layout_constraintEnd_toStartOf="@id/textE"
        app:layout_constraintTop_toTopOf="@id/textE" />

    <TextView
        android:id="@+id/textE"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginStart="16dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="E"
        android:textColor="@android:color/white"
        app:layout_constraintEnd_toStartOf="@+id/textF"
        app:layout_constraintStart_toEndOf="@+id/textD"
        app:layout_constraintTop_toTopOf="@+id/textD"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:background="#003cff"
        app:layout_constraintStart_toEndOf="@id/textE"
        app:layout_constraintTop_toTopOf="@+id/textE" />

    <View
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:background="#ff00cc"
        app:layout_constraintEnd_toStartOf="@id/textF"
        app:layout_constraintTop_toTopOf="@id/textF" />

    <TextView
        android:id="@+id/textF"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginStart="8dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="F"
        android:textColor="@android:color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textE"
        app:layout_constraintTop_toTopOf="@+id/textD"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="16dp"
        android:layout_height="35dp"
        android:background="#00ff19"
        app:layout_constraintStart_toEndOf="@id/textF"
        app:layout_constraintTop_toTopOf="@id/textF" />

    <TextView
        android:id="@+id/heading3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="spread_inside, match_constraints"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        android:textSize="16sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textD"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:background="#003cff"
        app:layout_constraintEnd_toStartOf="@id/textG"
        app:layout_constraintTop_toTopOf="@+id/textG" />

    <TextView
        android:id="@+id/textG"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="G"
        android:textColor="@android:color/black"
        app:layout_constraintEnd_toStartOf="@+id/textH"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/heading3"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="16dp"
        android:layout_height="35dp"
        android:background="#fffb00"
        app:layout_constraintEnd_toStartOf="@id/textH"
        app:layout_constraintTop_toTopOf="@id/textH" />

    <TextView
        android:id="@+id/textH"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginStart="16dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="H"
        android:textColor="@android:color/white"
        app:layout_constraintEnd_toStartOf="@+id/textI"
        app:layout_constraintStart_toEndOf="@+id/textG"
        app:layout_constraintTop_toTopOf="@+id/textG"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:background="#003cff"
        app:layout_constraintStart_toEndOf="@id/textH"
        app:layout_constraintTop_toTopOf="@id/textH" />

    <View
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:background="#ff00cc"
        app:layout_constraintEnd_toStartOf="@id/textI"
        app:layout_constraintTop_toTopOf="@id/textI" />

    <TextView
        android:id="@+id/textI"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginStart="8dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="I"
        android:textColor="@android:color/black"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textH"
        app:layout_constraintTop_toTopOf="@+id/textG"
        tools:ignore="HardcodedText" />

    <View
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:background="#ff00cc"
        android:visibility="gone"
        app:layout_constraintEnd_toStartOf="@id/textC"
        app:layout_constraintTop_toTopOf="@id/textC" />

    <View
        android:id="@+id/view8dp"
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:layout_marginStart="24dp"
        android:background="#ff00cc"
        app:layout_constraintBottom_toTopOf="@id/view8dpGap"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textG"
        app:layout_constraintVertical_bias="0.100000024"
        app:layout_constraintVertical_chainStyle="packed" />

    <TextView
        android:id="@+id/text8dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:text="8dp start margin"
        app:layout_constraintBottom_toBottomOf="@+id/view8dp"
        app:layout_constraintStart_toEndOf="@id/view8dp"
        app:layout_constraintTop_toTopOf="@+id/view8dp"
        tools:ignore="HardcodedText" />

    <View
        android:id="@+id/view8dpGap"
        android:layout_width="8dp"
        android:layout_height="35dp"
        android:layout_marginStart="24dp"
        android:layout_marginTop="8dp"
        android:background="#003cff"
        app:layout_constraintBottom_toTopOf="@+id/view16dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/view8dp" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:text="8dp gap not defined by start margin"
        app:layout_constraintBottom_toBottomOf="@+id/view8dpGap"
        app:layout_constraintStart_toEndOf="@+id/view8dpGap"
        app:layout_constraintTop_toTopOf="@+id/view8dpGap"
        tools:ignore="HardcodedText" />

    <View
        android:id="@+id/view16dp"
        android:layout_width="17dp"
        android:layout_height="35dp"
        android:layout_marginStart="24dp"
        android:layout_marginTop="8dp"
        android:background="#fffb00"
        app:layout_constraintBottom_toTopOf="@+id/view16dpGap"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/view8dpGap" />

    <TextView
        android:id="@+id/text16dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:text="16dp start margin"
        app:layout_constraintBottom_toBottomOf="@+id/view16dp"
        app:layout_constraintStart_toEndOf="@+id/view16dp"
        app:layout_constraintTop_toTopOf="@+id/view16dp"
        tools:ignore="HardcodedText" />

    <View
        android:id="@+id/view16dpGap"
        android:layout_width="17dp"
        android:layout_height="35dp"
        android:layout_marginStart="24dp"
        android:layout_marginTop="8dp"
        android:background="#00ff19"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/view16dp" />

    <TextView
        android:id="@+id/text16dpGap"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:text="16dp gap not defined by start margin"
        app:layout_constraintBottom_toBottomOf="@+id/view16dpGap"
        app:layout_constraintStart_toEndOf="@+id/view16dpGap"
        app:layout_constraintTop_toTopOf="@+id/view16dpGap"
        tools:ignore="HardcodedText" />

</android.support.constraint.ConstraintLayout>

In constraintLayout, chain-style worked like below

1.Spread: The views are evenly distributed. E.g. app:layout_constraintHorizontal_chainStyle=”spread” app:layout_constraintVertical_chainStyle=”spread”

2.Spread inside: The first and last view are affixed to the constraints on each end of the chain and the rest are evenly distributed. E.g. app:layout_constraintHorizontal_chainStyle=”spread_inside” app:layout_constraintVertical_chainStyle=”spread_inside”

3.Packed: The views are packed together (after margins are accounted for). You can then adjust the whole chain’s bias (left/right or up/down) by changing the chain’s head view bias. E.g. app:layout_constraintHorizontal_chainStyle=”packed” app:layout_constraintVertical_chainStyle=”packed”

4.Weighted: When the chain is set to either spread or spread inside, you can fill the remaining space by setting one or more views to “match constraints” (0dp). default, the space is evenly distributed between each view that's set to "match constraints," but you can assign a weight of importance to each view using thelayout_constraintHorizontal_weight and layout_constraintVertical_weight attributes. If you're familiar with layout_weight in a linear layout, this works the same way. So the view with the highest weight value gets the most amount of space; views that have the same weight get the same amount of space.

And for more information, you can refer to image below

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!