Wrap_content view inside a ConstraintLayout stretches outside the screen
Asked Answered
A

7

196

I am trying to implement a simple chat bubble using a ConstraintLayout. This is what I am trying to achieve:

enter image description here enter image description here

However, wrap_content does not do what I want. It respects the margins, but expands outside of the view bounds. Here is my layout:

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

    <TextView
        android:id="@+id/chat_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="16dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintHorizontal_bias="0"
        tools:background="@drawable/chat_message_bubble"
        tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sodales accumsan tortor at bibendum."
        android:layout_marginStart="64dp"
        android:layout_marginLeft="64dp"
        android:layout_marginEnd="32dp"
        android:layout_marginRight="32dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp" />
</android.support.constraint.ConstraintLayout>

This renders as follows:

enter image description here

I am using com.android.support.constraint:constraint-layout:1.0.0-beta4.

Am I doing something wrong? Is it a bug or just an unintuitive behavior? Can I achieve the proper behavior using a ConstraintLayout (I know I can use other layouts, I am asking about ConstrainLayout specifically).

Atalante answered 28/11, 2016 at 18:21 Comment(7)
can you post the text view along with its parent constraint layout? as you know, attributes of parent layout has great impact on childAnastassia
By the way, in your case i guess horizontal bias is the culprit. try removing layoutright to right of and biasAnastassia
Horizontal bias is necessary, otherwise if the bubble is centered. Without layout right to right the right margin won't be taken into account, which is not what we want. I tried to remove them, as you advised, but it didn't help.Atalante
problem is horizontal bias 0 for sure. I will check for the possible solutions and post it asap as I am also working with something similar on constraint layout.Anastassia
@MarcinJedynak sorry if this is off topic, but where did you get the chat bubble? Looks great.There
@There chat bubble comes from tools:background="@drawable/chat_message_bubble". To implement it you have to create chat_message_bubble.xml file in drawable folder then add this code: <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#FB4382"/> <corners android:radius="10dip"/> </shape>Accumulate
For me this is not working on chained views. So one view have wrap content, then get all space of whole chain screen. :(Lewellen
D
300

Outdated: See better answer

No, you cannot do what you want with ConstraintLayout as it is today (1.0 beta 4):

  • wrap_content only asks the widget to measure itself, but won't limit its expansion against eventual constraints
  • match_constraints (0dp) will limit the size of the widget against the constraints... but will match them even if wrap_content would have been smaller (your first example), which isn't what you want either.

So right now, you are out of luck for that particular case :-/

Now... we are thinking about adding extra capabilities to match_constraints to deal with this exact scenario (behaving as wrap_content unless the size ends being more than the constraints).

I cannot promise that this new feature will make it before the 1.0 release though.

Edit: we did add this capability in 1.0 with the attribute app:layout_constraintWidth_default="wrap" (with width set to 0dp). If set, the widget will have the same size as if using wrap_content, but will be limited by constraints (i.e. it won't expand beyond them)

Update Now those tags are deprecated, instead use layout_width="WRAP_CONTENT" and layout_constrainedWidth="true".

Diu answered 30/11, 2016 at 6:5 Comment(16)
But this wrap_content behavior might be counterintuitive as it differs from what you would expect from classic layouts, like LinearLayout. Is it intended? Could you give me an example scenario where this approach is better?Atalante
It's intended (it allows us to measure less), but that's not set in stone. We might either add more flexibility on match_constraints or change the way we deal with wrap_content.Diu
Thats a super issue for me. I can't use TextView with compound drawables right now because if I set it to match_constraints the compound drawable will be on the very right, even if there is very short text.Sikhism
This works absolutely perfectly! I will add that layout_constraintHorizontal_bias is another helpful attribute for cases like this. Otherwise when your text is very short the view will be centered by the two constraints as well as wrapped to content.Hearsay
@NicolasRoard: can u pls help me with constraint layout, i have an image in the upper half with a guideline of 0.4 and content below, but when i set the constraint layout to wrap_content it only picks 0.4 of the screen (and half of the textviews below are not visible), i used app:layout_constraintWidth_default="wrap" too, and v1.0.2 of the library but it doesnt helpFaustinafaustine
app:layout_constraintWidth_default="wrap" with width as 0dp does it nicely!Dexamyl
this should be EXPLICIT in the documentation/instructions.Tripe
Should the Edit move to have greater prominence? Kind of gets lost beneath the original. Appreciate the answer. Thanks @NicolasRoard .Introgression
I have a View with a width of wrap_content, it's constraintLeft="parent" and constraintRight a Guideline that is 80% of the width of the parent. If the View width is smaller than these constraints then it's centered between them. Is there a way to anchor it to the left and grow to the right, up to the Guideline? Apologies if this is confusingMiddle
Nvm I just realised that adding app:layout_constraintHorizontal_bias="0" to the View will workMiddle
wrap_content only asks the widget to measure itself, but won't limit its expansion against eventual constraints -> @NicolasRoard the question is “WHY” ? Why would a constraint engine not be in charge, especially given you have no priority system (like the iOS counterpart) because they “are complicated” which I understand, but this behavior is weird (and dare I say, not well documented, even as of constraint-layout:1.1.0-beta5Rory
the reason is bit complicated (mix of performance concerns and limitations of framework), so the current compromise felt the best solution; we might revisit this in the future. Agree on the documentation bit, we'll work on it.Diu
Thanks for the clarification, however, still as of 1.1.0 beta 6, I am not getting the desired behavior. I have a packed horizontal chain of text views that has variable length of text in each text view. now what I want is that they are streatched as much as the constraint it self, otherwise should be wrapped and centered, what I am getting is that no view is respecting the constraint. and are expanding indefintly. I am using the new attribute constrainedWidth ="true". finally resorted to setting maxWidth to all textviews not to expand more than desired! hope this gets fixed soon :(Beliabelial
@NicolasRoard Unfortunately it still doesn't work with Barriers. When my right constraint is parent then everything is OK but things go wrong when it's Barrier. Hopefully I was able to use another view as constraint (because it's visible every time) and it works but I would prefer to use Barrier for my particular case. Thanks anyway :)Overhang
@NicolasRoard If the text is small, because of both start and end constraints to parent, the text gets center aligned. However, I want it to be either towards start or end based on sender or receiver in chat. Any idea how to do this?Eulaliaeulaliah
@Eulaliaeulaliah you can use bias for your case. developer.android.com/reference/androidx/constraintlayout/…Cung
P
455

Updated (ConstraintLayout 1.1.+)

Use app:layout_constrainedWidth="true" with android:layout_width="wrap_content"

Previously (deprecated):

app:layout_constraintWidth_default="wrap" with android:layout_width="0dp"

Puggree answered 19/10, 2017 at 15:37 Comment(5)
True, since ConstraintLayout 1.1.0 beta 2, I believe. androidstudio.googleblog.com/2017/10/…Maighdiln
This now in the 1.1 release: medium.com/google-developers/…Androgynous
love stackoverflow! thanks this helped me! keep the wrap content, but never go beyond the constraint! #TILWaldrop
What an answer, didn't know this existed! Thanks man, after 2 hours of playing with alternatives this worked a treat!Feebleminded
You've made my dayCindy
D
300

Outdated: See better answer

No, you cannot do what you want with ConstraintLayout as it is today (1.0 beta 4):

  • wrap_content only asks the widget to measure itself, but won't limit its expansion against eventual constraints
  • match_constraints (0dp) will limit the size of the widget against the constraints... but will match them even if wrap_content would have been smaller (your first example), which isn't what you want either.

So right now, you are out of luck for that particular case :-/

Now... we are thinking about adding extra capabilities to match_constraints to deal with this exact scenario (behaving as wrap_content unless the size ends being more than the constraints).

I cannot promise that this new feature will make it before the 1.0 release though.

Edit: we did add this capability in 1.0 with the attribute app:layout_constraintWidth_default="wrap" (with width set to 0dp). If set, the widget will have the same size as if using wrap_content, but will be limited by constraints (i.e. it won't expand beyond them)

Update Now those tags are deprecated, instead use layout_width="WRAP_CONTENT" and layout_constrainedWidth="true".

Diu answered 30/11, 2016 at 6:5 Comment(16)
But this wrap_content behavior might be counterintuitive as it differs from what you would expect from classic layouts, like LinearLayout. Is it intended? Could you give me an example scenario where this approach is better?Atalante
It's intended (it allows us to measure less), but that's not set in stone. We might either add more flexibility on match_constraints or change the way we deal with wrap_content.Diu
Thats a super issue for me. I can't use TextView with compound drawables right now because if I set it to match_constraints the compound drawable will be on the very right, even if there is very short text.Sikhism
This works absolutely perfectly! I will add that layout_constraintHorizontal_bias is another helpful attribute for cases like this. Otherwise when your text is very short the view will be centered by the two constraints as well as wrapped to content.Hearsay
@NicolasRoard: can u pls help me with constraint layout, i have an image in the upper half with a guideline of 0.4 and content below, but when i set the constraint layout to wrap_content it only picks 0.4 of the screen (and half of the textviews below are not visible), i used app:layout_constraintWidth_default="wrap" too, and v1.0.2 of the library but it doesnt helpFaustinafaustine
app:layout_constraintWidth_default="wrap" with width as 0dp does it nicely!Dexamyl
this should be EXPLICIT in the documentation/instructions.Tripe
Should the Edit move to have greater prominence? Kind of gets lost beneath the original. Appreciate the answer. Thanks @NicolasRoard .Introgression
I have a View with a width of wrap_content, it's constraintLeft="parent" and constraintRight a Guideline that is 80% of the width of the parent. If the View width is smaller than these constraints then it's centered between them. Is there a way to anchor it to the left and grow to the right, up to the Guideline? Apologies if this is confusingMiddle
Nvm I just realised that adding app:layout_constraintHorizontal_bias="0" to the View will workMiddle
wrap_content only asks the widget to measure itself, but won't limit its expansion against eventual constraints -> @NicolasRoard the question is “WHY” ? Why would a constraint engine not be in charge, especially given you have no priority system (like the iOS counterpart) because they “are complicated” which I understand, but this behavior is weird (and dare I say, not well documented, even as of constraint-layout:1.1.0-beta5Rory
the reason is bit complicated (mix of performance concerns and limitations of framework), so the current compromise felt the best solution; we might revisit this in the future. Agree on the documentation bit, we'll work on it.Diu
Thanks for the clarification, however, still as of 1.1.0 beta 6, I am not getting the desired behavior. I have a packed horizontal chain of text views that has variable length of text in each text view. now what I want is that they are streatched as much as the constraint it self, otherwise should be wrapped and centered, what I am getting is that no view is respecting the constraint. and are expanding indefintly. I am using the new attribute constrainedWidth ="true". finally resorted to setting maxWidth to all textviews not to expand more than desired! hope this gets fixed soon :(Beliabelial
@NicolasRoard Unfortunately it still doesn't work with Barriers. When my right constraint is parent then everything is OK but things go wrong when it's Barrier. Hopefully I was able to use another view as constraint (because it's visible every time) and it works but I would prefer to use Barrier for my particular case. Thanks anyway :)Overhang
@NicolasRoard If the text is small, because of both start and end constraints to parent, the text gets center aligned. However, I want it to be either towards start or end based on sender or receiver in chat. Any idea how to do this?Eulaliaeulaliah
@Eulaliaeulaliah you can use bias for your case. developer.android.com/reference/androidx/constraintlayout/…Cung
A
38

Yep, as mentioned in answer given by Nikolas Roard you should add app:layout_constraintWidth_default="wrap" and set width to 0dp. And to align your bubble right you should set 1.0 for layout_constraintHorizontal_bias.

Here's the final source code:

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

    <TextView
        android:id="@+id/chat_message"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginStart="64dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintWidth_default="wrap"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:background="@drawable/chat_message_bubble"
        android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sodales accumsan tortor at bibendum." />

</android.support.constraint.ConstraintLayout>

As a result it looks like:

enter image description here

Accumulate answered 4/10, 2017 at 10:5 Comment(3)
I think that's because OP wants small bubble on left and yours is right, which changes requirementsDeterminism
important part here is app:layout_constraintHorizontal_bias="1.0"Immigration
yes, and if you want start instead of end to align, use app:layout_constraintHorizontal_bias="0" (note: floats aren't required)Quincuncial
C
13

Like the other answers already said, since ConstraintLayout 1.0 it's possible to achieve that, but as of the newest release (1.1.x) they've changed how you do it.

Since the release of ConstraintLayout 1.1 the old app:layout_constraintWidth_default="wrap" and app:layout_constraintHeight_default="wrap" attributes are now deprecated.

If you want to provide a wrap_content behavior, but still enforce the constraints on your View, you should set its width and/or height to wrap_content combined with the app:layout_constrainedWidth=”true|false” and/or app:layout_constrainedHeight=”true|false” attributes, as stated on the docs:

WRAP_CONTENT : enforcing constraints (Added in 1.1) If a dimension is set to WRAP_CONTENT, in versions before 1.1 they will be treated as a literal dimension -- meaning, constraints will not limit the resulting dimension. While in general this is enough (and faster), in some situations, you might want to use WRAP_CONTENT, yet keep enforcing constraints to limit the resulting dimension. In that case, you can add one of the corresponding attribute:

app:layout_constrainedWidth=”true|false” app:layout_constrainedHeight=”true|false”

As for the latest release, by the time I've answered this, ConstraintLayout is on version 1.1.2.

Coppock answered 15/6, 2018 at 3:55 Comment(0)
H
6

Deprecation of app:layout_constraintWidth_default text and its alternative

@nicolas-roard's answer of app:layout_constraintWidth_default="wrap" and android:layout_width="0dp" is now DEPRECATED.

Go ahead and use app:layout_constrainedWidth="true" and android:layout_width="wrap_content".

The reason for deprecation, I dont know. But its right in the source code of ConstraintLayout

Hauteloire answered 13/6, 2019 at 7:6 Comment(0)
D
-8

You should replace

android:layout_width="wrap_content"

with

android:layout_width="match_parent"

from your TextView and then adjust padding and margin accordingly. I have updated your code,

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

<TextView
    android:id="@+id/chat_message"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp"
    android:layout_marginEnd="10dp"
    android:layout_marginLeft="60dp"
    android:layout_marginRight="10dp"
    android:layout_marginStart="60dp"
    android:layout_marginTop="8dp"
    android:padding="16dp"
    app:layout_constraintTop_toTopOf="parent"
    tools:background="#c9c7c7"
    tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris sodales accumsan tortor at bibendum." />

You will get this result enter image description here

Domeniga answered 4/10, 2017 at 10:53 Comment(1)
You should avoid of using "match_parent" for any view in a ConstraintLayout. Look at "Note" hereAccumulate
N
-8

I use this one

app:layout_constraintEnd_toEndOf="parent"
Neufer answered 20/1, 2018 at 12:48 Comment(1)
how does this ans OP's question? how does this wrap content?Cindy

© 2022 - 2024 — McMap. All rights reserved.