Search code examples
androidandroid-layouttextviewandroid-xmlandroid-constraintlayout

Android - TextView inside a ConstraintLayout goes off to infinity to the right - how to pin with ImageView and have ellipsis too


I am trying to make my TextView has a dynamic width and an ImageView pinned to the end of it, inside of a ConstraintLayout. When the text is very long, I want to use an ellipsis and have the ImageView pin to the view to the right of it.

Here is an example of what I am trying to achieve visually:

enter image description here

enter image description here

With my code, I am able to achieve the first image with thisIsShortText but when I have long text, it looks bad, like this:

enter image description here

enter image description here

The TextView and ImageView just go off to the right to infinity. Can anyone help me fix this? This is the XML code I have. If you just put it into your Android Studio it will look like my images. Thank you:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="70dp">

    <!-- This view does not move or change size. -->
    <View
        android:id="@+id/firstView"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="@android:color/holo_red_dark"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </View>

    <!-- This view's width is dynamic and changes size based on it's text length.
     If the length of text is too long to fit, it uses an ellipsize. -->
    <TextView
        android:id="@+id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:ellipsize="end"
        android:maxLines="1"
        android:text="thisIsVeryLongTextThatIsTooLongAndIsLong"
        android:textColor="@color/primary_text_dark"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/firstView"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- This view is pinned to the end of textView. -->
    <ImageView
        android:id="@+id/imageview"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_marginStart="8dp"
        android:background="@android:color/holo_purple"
        android:src="@android:drawable/ic_dialog_info"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/textview"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- This view does not move or change size. -->
    <View
        android:id="@+id/secondView"
        android:layout_width="80dp"
        android:layout_height="35dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:background="@android:color/holo_blue_light"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/thirdView"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- This view does not move or change size. -->
    <View
        android:id="@+id/thirdView"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:background="@android:color/holo_orange_dark"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Solution

  • You can achieve that by adding the below to the TextView:

    • Enabling width constraints.
    • Using a packed chain with a 0 horizontal bias.
    • Constraint the end to the start of the right view (imageview)

    And constraint the end of the info imageview to the start of the secondView

    So, you need to add the following to the textview:

        app:layout_constrainedWidth="true"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintEnd_toStartOf="@id/secondView"
    

    And to the imageview:

        app:layout_constraintEnd_toStartOf="@+id/secondView"
    

    Now the entire layout:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.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="70dp">
    
        <!-- This view does not move or change size. -->
        <View
            android:id="@+id/firstView"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:background="@android:color/holo_red_dark"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
    
        </View>
    
        <!-- This view's width is dynamic and changes size based on it's text length.
         If the length of text is too long to fit, it uses an ellipsize. -->
        <TextView
            android:id="@+id/textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:ellipsize="end"
            android:maxLines="1"
            android:text="thisIsVeryLongTextThatIsTooLongAndIsLong"
            android:textColor="@color/primary_text_dark"
            android:textSize="16sp"
            app:layout_constrainedWidth="true"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@id/imageview"
            app:layout_constraintHorizontal_bias="0"
            app:layout_constraintHorizontal_chainStyle="packed"
            app:layout_constraintStart_toEndOf="@id/firstView"
            app:layout_constraintTop_toTopOf="parent" />
    
        <!-- This view is pinned to the end of textView. -->
        <ImageView
            android:id="@+id/imageview"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"
            android:background="@android:color/holo_purple"
            android:src="@android:drawable/ic_dialog_info"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/secondView"
            app:layout_constraintStart_toEndOf="@id/textview"
            app:layout_constraintTop_toTopOf="parent" />
    
        <!-- This view does not move or change size. -->
        <View
            android:id="@+id/secondView"
            android:layout_width="80dp"
            android:layout_height="35dp"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp"
            android:background="@android:color/holo_blue_light"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@id/thirdView"
            app:layout_constraintTop_toTopOf="parent" />
    
        <!-- This view does not move or change size. -->
        <View
            android:id="@+id/thirdView"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:background="@android:color/holo_orange_dark"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    Preview:

    enter image description here