Marcin Jedynak
Marcin Jedynak

Reputation: 3847

Wrap_content view inside a ConstraintLayout stretches outside the screen

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).

Upvotes: 202

Views: 99608

Answers (7)

Nicolas Roard
Nicolas Roard

Reputation: 8449

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

Upvotes: 301

Silvia H
Silvia H

Reputation: 8357

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"

Upvotes: 459

Bolaji
Bolaji

Reputation: 566

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

Upvotes: 6

Mauker
Mauker

Reputation: 11487

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.

Upvotes: 13

jsHate
jsHate

Reputation: 599

I use this one

app:layout_constraintEnd_toEndOf="parent"

Upvotes: -8

Mehul
Mehul

Reputation: 2149

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

Upvotes: -8

Eugene Brusov
Eugene Brusov

Reputation: 17846

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

Upvotes: 39

Related Questions