Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConstraintLayout: Compound ImageView that stays in parent when text expands

Consider the following layout:

<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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        android:padding="8dp"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Text" />

    <ImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintStart_toEndOf="@id/text_view"
        app:layout_constraintTop_toTopOf="parent"
        tools:background="@android:color/black" />
</android.support.constraint.ConstraintLayout>

The image view (or button, or any other widget, important is that it has a fixed size) is aligned right/end of a TextView with a size of wrap_content, thus, the text itself only takes the space it needs.

What I now want is, when the text expands (aka if it's longer), that the button gets aligned to the right of the parent, and the text view only gets the width that is left and gets ellipsized. At the moment, the image view is pushed outside and the text gets ellipsized once it fills the whole parent.

I tried to fix this by adding a endToEnd="parent" constraint the the image and setting the horizontal bias to 0 (see code), but that doesn't work.

Any suggestions on what I could do instead?

like image 225
Maxr1998 Avatar asked Feb 01 '26 23:02

Maxr1998


1 Answers

In order to prevent the ImageView from getting pushed outside the parent you need to constrain the end of the TextView to the start of the ImageView to create a chain. Now to ensure that the TextView only takes the space it needs but also has its constraints enforced, you need to add app:layout_constrainedWidth="true" attribute to your TextView.

If you want the ImageView to stay immediately to the right of the TextView can use packed chain style with a horizontal bias of 0. If you want the ImageView to be aligned to the right of the parent you can use the spread_inside chain style without bias.

The resulting XML with above changes might look like this:

<?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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        android:padding="8dp"
        android:textSize="18sp"
        app:layout_constrainedWidth="true"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/image_view"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Text" />

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="48dp"
        android:layout_height="48dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/text_view"
        app:layout_constraintTop_toTopOf="parent"
        tools:background="@android:color/black" />
</android.support.constraint.ConstraintLayout>

EDIT: As requested in the comment, here's how it would work with a Barrier sparating the 3 TextViews and the ImageView. In this case you don't specify the constraints for the ends of the TextViews thus you no longer have them chained horizontally. Instead, you create a Barrier with the direction being the end of all TextViews that are referenced in the Barrier. This will ensure that the Barrier is always at the end of the widest TextView. The last thing to do is to constrain the start side of the ImageView to the Barrier.

Example XML:

<?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:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/text_view1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        android:padding="8dp"
        android:textSize="18sp"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintBottom_toTopOf="@id/text_view2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Text1" />

    <TextView
        android:id="@+id/text_view2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        android:padding="8dp"
        android:textSize="18sp"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintBottom_toTopOf="@id/text_view3"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text_view1"
        tools:text="Text2" />

    <TextView
        android:id="@+id/text_view3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        android:padding="8dp"
        android:textSize="18sp"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text_view2"
        tools:text="Text3" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="end"
        app:constraint_referenced_ids="text_view1,text_view2,text_view3" />

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="48dp"
        android:layout_height="48dp"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/barrier"
        app:layout_constraintTop_toTopOf="parent"
        tools:background="@android:color/black" />
</android.support.constraint.ConstraintLayout>
like image 90
Pawel Laskowski Avatar answered Feb 04 '26 14:02

Pawel Laskowski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!