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

半腔热情 提交于 2019-12-12 08:25:59

问题


I have had a couple of my layouts blow up since changing over to ConstraintLayout version 1.1.0-beta4. Before I make any changes, I want to get a better understanding of how margins work in ConstraintLayout chains. In the following, I compare a layout in ConstraintLayout version 1.0.2 to version 1.1.0-beta4, but I believe that the issue first arose in 1.1.0-beta2.

My goal is to have some text views stretch across the screen with gaps between the 1st and 2nd text views and the 2nd and 3rd text views. The background should show in these margins. To do this, I create a horizontal chain and specify an end margin from the left text view to the center text view and an end margin from the center text view to the right text view. The horizontal chain style is spread_inside.

Example 1 - Using ConstraintLayout version 1.0.2

This is how things look in version 1.0.2 and is what I expect.

<android.support.constraint.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@android:color/holo_blue_light">

    <TextView
        android:id="@+id/tvLeft"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginEnd="8dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="Text1"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/tvCenter"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/tvCenter"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:layout_marginEnd="8dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="Text2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/tvRight"
        app:layout_constraintStart_toEndOf="@+id/tvLeft"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

    <TextView
        android:id="@+id/tvRight"
        android:layout_width="0dp"
        android:layout_height="35dp"
        android:background="@android:color/white"
        android:gravity="center"
        android:text="Text3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/tvCenter"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="HardcodedText" />

</android.support.constraint.ConstraintLayout>

Example 2 - Using ConstraintLayout version 1.1.0-beta4

This same layout looks like the following in version 1.1.0-beta4 of ConstraintLayout. Notice that the margins have disappeared. I expect that this should look the same as example 1, but it doesn't.

Example 3 - Using ConstraintLayout version 1.1.0-beta4 with start margin

If I take this same layout and simply add a start margin of 8dp to the right text view (tvRight), my margins reappear not only between the center and right text views but also between the left and center textviews although I have not changed the margins there.

This is more than just the previously set margins suddenly being honored. If I set the start margin on the rightmost text view to '48dp', what appears to be a 48dp margin also appears between the left and center text views.

<android.support.constraint.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@android:color/holo_blue_light">

<!-- TextViews tvLeft & tvRight not shown but are the same as above.-->

<TextView
    android:id="@+id/tvRight"
    android:layout_width="0dp"
    android:layout_height="35dp"
    android:layout_marginStart="48dp"
    android:background="@android:color/white"
    android:gravity="center"
    android:text="Text3"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@+id/tvCenter"
    app:layout_constraintTop_toTopOf="parent"
    tools:ignore="HardcodedText" />

</android.support.constraint.ConstraintLayout>  

So, my question is, "Why am I seeing these results?" How are margins handled in ConstraintLayout chains, especially spread_inside chains? Has there been a change in the way chain margins are handled, or am I missing something? I am looking for an explanation or a reference to some documentation that explains all this.


回答1:


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.




回答2:


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>



回答3:


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



来源:https://stackoverflow.com/questions/47931430/how-do-margins-in-chains-work-in-constraintlayout-1-1-0-beta

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