I recently started using ConstraintLayout. As I discovered, most of the features are pretty straight forward, and well explained in the docs with samples, text and video tutorials and all.
The thing that got in my mind is how to I solve this 'puzzle' as elegant as possible?
As you can see, in the right section of the layout, I have multiple Views aligned left. On the last but one row, there are 3 Views aligned horizontally (they are also aligned TOP between each other).
Problem is: if I set first View's visibility from that row as GONE, the other two (in the same row), go left as expected, but the one underneath (last row in the vertical alignment) goes over the row before (because its constraintTop property is set as bottom of the View set as GONE).
The only solution I can think of is using a ViewGroup to group those 3 Views and add the constraint to last row View to it.
Am I missing some property on ConstraintLayout which could help my case? Maybe some sort of fallback (or multiple) constraints if one of them is set on a GONE View?
Sorry if my explanation seem quite abstruse, maybe the pictures will help you more :)
LE: Added layout: https://gist.github.com/DoruAdryan/7e7920a783f07b865489b1af0d933570
You can use the new Barriers feature of ConstraintLayout.
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.AppCompatImageView
android:id="#+id/iv_item_small_product_image"
android:layout_width="113dp"
android:layout_height="113dp"
android:layout_marginLeft="7dp"
android:layout_marginStart="7dp"
android:background="#android:drawable/btn_radio"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.AppCompatImageView
android:id="#+id/iv_row_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:background="#android:drawable/bottom_bar"
app:layout_constraintLeft_toRightOf="#+id/iv_item_small_product_image"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ro.emag.android.views.FontTextView
android:id="#+id/tv_row_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="3dp"
android:ellipsize="end"
android:maxLines="2"
app:layout_constraintLeft_toRightOf="#+id/iv_item_small_product_image"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/iv_row_1"
app:layout_goneMarginTop="0dp"
tools:text="Some text long enough to be split on multiple lines on some devices." />
<android.support.v7.widget.AppCompatRatingBar
android:id="#+id/rb_row_3_1"
style="#style/Widget.AppCompat.RatingBar.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="9dp"
android:isIndicator="true"
android:numStars="5"
android:stepSize="0.1"
app:layout_constraintLeft_toRightOf="#+id/iv_item_small_product_image"
app:layout_constraintTop_toBottomOf="#id/tv_row_2" />
<TextView
android:id="#+id/tv_row_3_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginStart="6dp"
android:layout_marginTop="9dp"
app:layout_constraintLeft_toRightOf="#+id/rb_row_3_1"
app:layout_constraintTop_toBottomOf="#id/tv_row_2"
tools:text="106" />
<TextView
android:id="#+id/tv_row_3_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_marginStart="6dp"
android:layout_marginTop="9dp"
app:layout_constraintLeft_toRightOf="#+id/tv_row_3_2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#id/tv_row_2"
app:layout_goneMarginLeft="0dp"
app:layout_goneMarginStart="0dp"
tools:text="Options available" />
<android.support.constraint.Barrier
android:id="#+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="rb_row_3_1, tv_row_3_2, tv_row_3_3" />
<TextView
android:id="#+id/tv_row_4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="3dp"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintLeft_toRightOf="#+id/iv_item_small_product_image"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/barrier"
tools:text="Some text on last row" />
</android.support.constraint.ConstraintLayout>
Now, the last row is depending on the barrier instead of one of the views of the third row. As the barrier is depending on the three views of the second row, you won't have the gone margin problem.
Plus, i noticed that you don't need the guideline. The right segment can depend on the imageview directly.
In case you are not familiar with Barriers, here's a link to help you out.
As this feature is available only in the 1.1.0 beta1 release of ConstraintLayout, don't forget to add this line to your build.gradle file.
compile 'com.android.support.constraint:constraint-layout:1.1.0-beta1'
make sure to include maven { url "https://maven.google.com" }
Related
I am developing news app and I want to implement constrainlayout inside CardView and achieve ui the same as image below
but I could achieve what I want below my xml file
where I have implemented constrainlayout inside cardview
<TextView
android:id="#+id/articleTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/articleTitle"
tools:ignore="NotSibling" />
<TextView
android:id="#+id/articleAuthor"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="hhhhh"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/imageView" />
<TextView
android:id="#+id/articleImageView"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/articleTitle" />
<TextView
android:id="#+id/articleDescription"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="hhhhh"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/imageView" />
<ImageView
android:id="#+id/articleImageUrl"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="#id/articleTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
below my xml ui output from layouteditor
What you need to achieve is not difficult at all (although, it's hard to tell because I don't know your project).
Based upon the image you provided, here's a rough approximation using basic Constraint Layout features (no Chains, or anything too fancy); again, I don't know the exact specs and requirements, but this should serve as a starting point.
Here's how the final product looks in the Android Studio Editor, I didn't run this, so there are some artifacts not 100% correctly rendered (like the borders of the CardView), because Android Studio does an "approximation" of how it looks:
Root Layout
You mentioned you wanted a CardView, so the root is naturally a MaterialDesign Card View:
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:background="#android:color/darker_gray"
android:elevation="4dp">
Constraint Layout
Inside the card view, there's one single viewGroup: a Constraint Layout
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/innerRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white">
This ConstraintLayout is going to contain all the Card's contents in a flat hierarchy. It matches its parent (the card) in width, but it wraps its height, just like the Card itself.
Top News Header, Icon, and subtext:
THere are various ways to achieve this, and depending upon your requirements, you may want to play with vertical chains, constraining the width, etc., to avoid text from overlapping each other, and/or to enable/disable multi-line support, or ellipsis, etc. None of this information can be inferred from your static image.
<ImageView
android:id="#+id/topFlameImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="Header title"
android:padding="8dp"
android:src="#drawable/ic_flash_on_black_24dp"
android:tint="#android:color/holo_red_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/topTitleTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Top News"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/topFlameImageView"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/bottomTitleTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Editor on duty: Dan"
android:textColor="#android:color/darker_gray"
app:layout_constraintBottom_toBottomOf="#id/topFlameImageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/topFlameImageView"
app:layout_constraintTop_toBottomOf="#id/topTitleTextView" />
Notice it's just an ImageView, and two TextViews, one below the other, all constrained together.
Big Image
I didn't put an image, but did add a blue background representing the image. I gave it an arbitrary height of 250dp, but this is not mandatory, you may change this; it gives you an idea.
This image is constrained to be below the above header with "Top News", etc, and it spans the whole width of the card.
<ImageView
android:id="#+id/bigImage"
android:layout_width="0dp"
android:layout_height="250dp"
android:background="#android:color/holo_blue_dark"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/topFlameImageView" />
Title + Icon
Below the big image, there's what appears to be a Title (and its icon). Nothing special, just like the "header" above, an image and a text.
Here is where there's something that I didn't do: In your image, the text in this, aligns to the left/start, even below the icon; in this example, the TextView is constrained to the end/right of the icon, and so if it's multi-line, it will not "properly" justify its text to fit below the icon. In other words, in the image above, the word "Update" should be below the red "lightning bolt" icon, but it's not. (I think it looks better this way anyway... but I haven't thought how to make it look like what you exactly want). Using drawableStart in the TextView, doesn't give the same effect, so that's why I used a separate imageVIew for these "icons", to better control the image's placement.
<ImageView
android:id="#+id/titleImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:contentDescription="Title"
android:padding="8dp"
android:src="#drawable/ic_flash_on_black_24dp"
android:tint="#android:color/holo_red_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/bigImage" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/titleTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Real Madrid provide Toni Kroos injury update"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#id/titleImageView"
app:layout_constraintTop_toTopOf="#id/titleImageView" />
User Avatar, Name, and Timestamp (?)
This is similar to the Title, and the Header at the beginning, except you want the timestamp (17 m) to be at the end/right of what appears to be the user name Onefootball.
<ImageView
android:id="#+id/userAvatarImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:contentDescription="Title"
android:padding="8dp"
android:src="#drawable/ic_account_circle_black_24dp"
android:tint="#android:color/holo_green_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/titleTextView" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/userNameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Onefootball"
android:textColor="#android:color/black"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="#id/userAvatarImageView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="#id/titleImageView"
app:layout_constraintTop_toTopOf="#id/userAvatarImageView" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/timestampTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:text="- 17m"
android:textColor="#android:color/darker_gray"
android:textSize="14sp"
app:layout_constraintBaseline_toBaselineOf="#id/userNameTextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="#id/userNameTextView" />
One image, one Text, another text; nothing fancy.
Closing the tags
Last but not least, you have to close the ConstraintLayout and the CardView...
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
And that's all.
Final Comment | Conclusion
At the beginning of this combo, I told you StackOverflow is not a Free Coding Site; this is still true, and I've made this effort because it seems like you are learning Android and I love helping people, but keep in mind that in general, it's much much better if you try firsts and come up with 20 different small questions as you go through it.
I would have personally tried to solve this in small bits (like I presented it above) and when something didn't behave as expected, it would have been easier to ask here "Hey look at this small thing, why doesn't it do X Y Z????" than to try to post the whole thing, and hope someone comes around and fixes it for you so you can copy paste the solution and forget about it.
I really hope you learn from this and don't just copy/paste it.
Good luck with your project.
I am using ConstraintLayout to create below xml in my application.
As you can see my first item is fine, But in the second one, some parts of my textView are not on the screen!
This is my XML code:
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/ly_user"
android:padding="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
app:layout_constraintRight_toRightOf="parent"
android:id="#+id/im_user_icon"
android:layout_width="#dimen/default_message_icon_size"
android:layout_height="#dimen/default_message_icon_size"
android:src="#drawable/user_pacific"/>
<ImageView
app:layout_constraintTop_toBottomOf="#+id/im_user_icon"
app:layout_constraintRight_toLeftOf="#+id/im_user_icon"
android:id="#+id/im_user_arrow"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/arrow_bg1"/>
<View
android:id="#+id/view_user_guidLine"
android:layout_width="1dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="#id/im_user_arrow"
app:layout_constraintRight_toRightOf="#id/im_user_arrow"/>
<TextView
app:layout_constraintTop_toBottomOf="#+id/im_user_icon"
app:layout_constraintRight_toLeftOf="#+id/view_user_guidLine"
android:id="#+id/tv_user_message"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="right"
android:padding="8dp"
android:minWidth="#dimen/default_message_textarea_width"
android:minHeight="#dimen/default_message_textarea_height"
android:background="#drawable/bg_right_text"
android:textColor="#android:color/white"/>
</android.support.constraint.ConstraintLayout>
I Know I can fix this problem to adding below line to the textView, But I need my textView be wrapContent.
app:layout_constraintLeft_toLeftOf="parent"
You can set your TextView's width to wrap_content, but to prevent it from expanding outside of screen you need to add the left constraint as well and use app:layout_constrainedWidth="true" to enforce constraints.
Now, to make the TextView stick to the right, you need to add app:layout_constraintHorizontal_bias="1", which will align it to its right constraint.
So all in all, these are the changes needed for the TextView:
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="1"
android:layout_width="wrap_content"
Add these following line in your code in your TextView
app:layout_constraintWidth_percent="0.6"
first line layout_constraintWidth_percent is 60 percent of your phone screen width you can change it according to your need.
Accepted answered works but on my side I use android:layout_width="0dp" because my TextView is in the middle of two elements.
<TextView
android:id="#+id/my_id_text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="#string/long_text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/second_vertical_divider_view"
app:layout_constraintStart_toEndOf="#+id/first_vertical_divider_view"
app:layout_constraintTop_toTopOf="parent" />
Accepted answer didn't helped in my case. Alternative solution can look like that:
<ConstraintLayout>
<TextView
android:id="#+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
app:layout_constraintEnd_toStartOf="#+id/option_info"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_max="wrap" />
<ImageView
android:id="#+id/option_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_info"
app:layout_constraintBottom_toBottomOf="#+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/title"
app:layout_constraintTop_toTopOf="#+id/title" />
</ConstraintLayout>
The idea is to prevent one view pushing another while expanding by creating a chain and add some constraint params to hold influenced view in view's border.
Hope it still will help somebody!
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.
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
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.
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.
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>
I'm designing my constraint layout using XML.
I have an OpenSansBTextView and I need my text to be centered in it. It's centered horizontally, and not centered vertically. I don't know why. Here is my xml file. Can you see my mistake?
<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:background="#color/colorAccent"
android:id="#+id/dashboard">
<com.doyousonder.android.utils.RochesterTextView
android:id="#+id/YourActivity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="25dp"
app:layout_constraintVertical_bias="0.34"
android:text="#string/YourActivity"
android:textColor="#color/colorPrimaryMoreDark"
android:textSize="23sp" />
<com.doyousonder.android.utils.OpenSansRTextView
android:id="#+id/YouVoted"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/YourActivity"
android:layout_marginTop="15dp"
android:layout_marginStart="20dp"
android:text="#string/YouVoted"
android:textColor="#color/colorPrimaryMoreDark"
android:textSize="15sp" />
<com.doyousonder.android.utils.OpenSansSBTextView
android:id="#+id/VoteCount"
android:layout_width="29dp"
android:layout_height="35dp"
app:layout_constraintStart_toEndOf="#+id/YouVoted"
app:layout_constraintTop_toTopOf="#+id/YouVoted"
app:layout_constraintBottom_toBottomOf="#+id/YouVoted"
android:layout_marginStart="5dp"
android:background="#drawable/more_curved_edge_button_button_primarycolor_background"
android:gravity="center"
android:text="1"
android:textAlignment="center"
android:textSize="25sp" />
You haven't provided much code to work with, i.e what is the youVoted variable. I'm assuming youvoted is your parent layout
I think you're issue comes with how you set up your constraints. Try these instead
...other layout info
app:layout_constraintBottom_toBottomOf="#+id/YouVoted"
app:layout_constraintStart_toStartOf="#+id/YouVoted"
app:layout_constraintTop_toTopOf="#+id/YouVoted"
app:layout_constraintEnd_toEndOf="#+id/YouVoted"/>
Explanation
I believe the mistake is you made is stating your textview should start at the end of your youvoted layout instead of saying it should start at the start of the youvoted layout.
change app:layout_constraintStart_toEndOf="#+id/YouVoted" to app:layout_constraintStart_toStartOf="#+id/YouVoted"
also add an end constraint.
app:layout_constraintEnd_toEndOf="#+id/YouVoted"
I have a XML layout for a ViewHolder inside a RecyclerView.
This layout's root is a ConstraintLayout whose height is set to wrap_content.
Inside this flat hierarchy there are 3 textviews and an image view with a fixed height; think of:
<ConstraintLayout>
<TextView height=wrap>
<TextView height=wrap>
<TextView height=wrap>
<ImageView height=150dp>
</ConstraintLayout>
It's a relatively simple layout. In beta4 this is how it looks in the Designer (and eventually at runtime, each recyclerView cell):
Apologies for the "red tape" but it's NDA blah blah.
That being said, the elements are:
The 3 text views (red taped with a nice purple background)
The ImageView with 150dp height is the gray thing.
The Purple background was applied to the root ConstraintLayout. All nice.
Now this is how it looks, without a single modification with Beta 5:
As you can see the Purple (root) Constraint Layout is now "confused" and doesn't wrap content as it used to.
Things I tried:
Adding app:layout_constraintHeight_default="wrap" to the ConstraintLayout (and spread too). Didn't make a difference.
The ImageView has a app:layout_constraintBottom_toBottomOf="parent" constraint that I tried removing, didn't make a difference either.
Revert back to beta4 :)
For the record, this is the full layout (id's have been renamed for red-tape reasons and no tools:text or similar due to the same reasons). The layout is otherwise exactly the same.
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorAccent">
<TextView
android:id="#+id/toplabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text=""
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="#+id/top_bottom_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="#+id/top_right_label"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/top_right_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:gravity="end"
android:maxLines="1"
android:text=""
app:layout_constraintBottom_toTopOf="#+id/top_bottom_label"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintLeft_toRightOf="#+id/toplabel"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="#+id/top_bottom_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:gravity="end"
android:maxLines="1"
android:text=""
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintLeft_toRightOf="#+id/toplabel"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/top_right_label" />
<ImageView
android:id="#+id/imageview"
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/top_bottom_label"
app:srcCompat="#android:color/darker_gray" />
</android.support.constraint.ConstraintLayout>
Am I supposed to do something different? (I know I can replace this with a RelativeLayout and probably do the same, but anyway… I believe in ConstraintLayout!) :)
I filed a bug about this and I got a workaround.
It's a regression and will be fixed (we hope) but… turns out my Chain is also incorrectly defined. My top_bottom_label does not have a bottom endpoint, and according to the documentation elements in a chain should be connected on both endpoints.
So I added app:layout_constraintBottom_toTopOf="#id/imageview" to the top_bottom_label and this seems to work for my case. I have, effectively added the imageView to the chain, even do I don't really care much for it. It works for now.
Update February 14th 2017: The ConstraintLayout team # Google fixed the issue in master. It will likely be fixed in a next release. (Thanks!).