How can I prevent a TextView in a ConstraintLayout Chain from pushing other TextViews beyond their constraints while using layout_constrainedWidth?
Asked Answered
A

3

16

My end goal is to have two single-line TextViews in a left-aligned, packed horizontal chain that allows both of them to grow to fill the remaining space, splitting it evenly if necessary, ellipsizing when there's not space.

Visual Aid: enter image description here

And here's the layout code that I've tried to accomplish this:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        tools:text="@tools:sample/lorem"
        app:layout_constrainedWidth="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/textView2"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="4dp"
        android:ellipsize="end"
        android:maxLines="1"
        tools:text="@tools:sample/lorem"
        app:layout_constrainedWidth="true"
        app:layout_constraintStart_toEndOf="@id/textView1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />

</android.support.constraint.ConstraintLayout>

As you can see, I've laid out two textviews in a horizontal chain. I've got the chain style set to packed so that they stay together. I've got the horizontal bias set to 0 so that the chain is left aligned. I've got the width set to wrap_content so that they don't stretch when the text is short, and I've also set app:layout_constrainedWidth="true" so that they don't go past their bounds when the text is long. This works almost exactly how I want except when the text in textView2 grows. As textView1 grows, it pushes textView2 to the right until it hits its constraint, at which point it ellipsizes (as expected/desired), but the same is not true for textview2. As textView2 grows, it stretches to fill the room to its right, but once it hits its constraint, instead of ellipsizing, it keeps stretching and starts to push textView1 to the left until it is no longer visible at all.

Visual aid (actual behavior):

enter image description here

I've tried to use things like setting layout_constraintHorizontal_weight to .5 on each view but that has no effect unless I change both view widths to 0dp (match_constraints) which breaks the scenario where both views have short text (it adds extra space between the two text views).

What it feels like is that when you combine width=wrap_content with layout_constrainedWidth=true, the weight values are ignored. Is this just a limitation of ConstraintLayout? I've spent a lot of time trying to figure out a way to make this work and right now it doesn't seem like it's possible. I've fallen back to using a LinearLayout and making some design compromises, but I'd really like to get this working if anyone has any ideas. Thanks!

Apical answered 13/7, 2018 at 23:42 Comment(4)
Have you tried setting app:layout_constraintWidth_min="someVal" on the left view to keep it from shrinking to 0?Reconnaissance
That I haven't tried. Sounds like it could help the view from going away completely but it still wouldn't get me exactly what I want since the string I use could be shorter than my minimum which would result in empty space and technically I'm ok with a minimum width of 0 for an empty string in that first view. Appreciate the suggestion, I might be able to work with that in the meantimeApical
Do You accept solution in code?Vibrations
@Vibrations it depends...if it's just initializing things in code that can't be done in xml then yes, but something that measures the text and adjusts the layout accordingly would defeat the purpose of this question as I'm specifically trying to get this to work "naturally" using ConstraintLayout properties, and at that point I could just make a custom view or really use any kind of viewApical
F
5

If someone is still looking for an answer, I think the following code will help.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/text1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintWidth_max="wrap"
        app:layout_constraintWidth_percent="0.5"
        android:maxLines="1"
        android:ellipsize="end"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/text2"
        app:layout_constraintHorizontal_chainStyle="packed"
        android:background="#ff0000"
        android:text="This is what you are looking for ?"
        />

    <TextView
        android:id="@+id/text2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintWidth_max="wrap"
        app:layout_constraintWidth_percent="1"
        android:maxLines="1"
        android:ellipsize="end"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toEndOf="@id/text1"
        app:layout_constraintEnd_toEndOf="parent"
        android:background="#ee0"
        android:text="This is a Long Text TextView2 And not something else"
        />

</android.support.constraint.ConstraintLayout>
Folia answered 7/9, 2019 at 11:40 Comment(0)
D
0

I needed a fix in the another answers.

And performs the following actions.

enter image description here

            <TextView
                android:id="@+id/first_tv"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:maxLines="1"
                app:layout_constraintHorizontal_bias="0" <!-- if you want gravity left -->
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toStartOf="@id/second_tv"
                app:layout_constraintHorizontal_chainStyle="packed"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintWidth_default="wrap"
                tools:text="ABCDEFGHIJKLMNOPQRSTU" />

            <TextView
                android:id="@+id/second_tv"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="2dp"
                android:ellipsize="end"
                android:maxLines="1"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@id/first_tv"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintWidth_default="wrap"
                tools:text="VWXYZ" />
Dredi answered 14/2, 2020 at 4:48 Comment(0)
H
-1

In ConstraninLayout if you want set weight such as linearLayout's weight , you should set value between 0..1 in (layout_constraintWidth_percent):

 app:layout_constraintWidth_percent="1"
 or
 app:layout_constraintWidth_percent="0.5"

and also  connect the beginning and the end of component to each other:

 app:layout_constraintStart_toEndOf="@id/textView1"
 app:layout_constraintEnd_toStartOf="@id/textView2"

completed code:

  <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="match_parent">
    <TextView
        android:id="@+id/textView1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/textView2"
        app:layout_constraintWidth_percent="0.5"
        android:background="@color/yellow_light"
        android:text="This is a long text that showing in textview1.This textview is a expanded textview.if you don't set (android:maxLines='1'),the whole text will be show." />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/textView1"
        app:layout_constraintWidth_percent="1"
        android:background="@color/orange_dark"
        android:maxLines="1"
        android:text="This is a long text that showing in textview2 that set (android:maxLines='1')" />

</androidx.constraintlayout.widget.ConstraintLayout>

enter image description here

Hesitancy answered 29/9, 2019 at 7:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.