Search code examples
androidandroid-linearlayoutandroid-viewandroid-constraintlayout

Align a set of views to the right of the largest view of those appearing in the right part of the screen


Can I use a ConstraintLayout to create a view that aligns children views to based on the largest child view?
Example:
enter image description here

Taking into account that the right Text printed can be larger in one of the rows, I'd like to have the progress bars be aligned to the largest Text on the right.
Is that possible? I can do it with nested LinearLayout but was wondering if ConstraintLayout solves this


Solution

  • Create a Barrier with start direction and reference all the IDs of the TextViews on the right. Constrain the end of each progress bar to the Barrier. The Barrier will be aligned to the start of the longest TextView.

    Sample XML of how to achieve this:

    <?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="match_parent">
    
        <androidx.constraintlayout.widget.Barrier
                android:id="@+id/barrier"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:barrierDirection="start"
                app:constraint_referenced_ids="text1,text2"/>
    
        <TextView
                android:id="@+id/progress1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="ProgressBar"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintEnd_toStartOf="@id/barrier" />
    
        <TextView
                android:id="@+id/progress2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="ProgressBar"
                app:layout_constraintTop_toBottomOf="@id/progress1"
                app:layout_constraintEnd_toStartOf="@id/barrier" />
    
        <TextView
                android:id="@+id/text1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Text"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintEnd_toEndOf="parent" />
    
        <TextView
                android:id="@+id/text2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Longer Text"
                app:layout_constraintTop_toBottomOf="@id/text1"
                app:layout_constraintEnd_toEndOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    Result: result

    To prevent the left TextView from overlapping with other Views you need to constrain its end to progress bar, set horizontal bias to 0 so that it's aligned to its start constraint and also set app:layout_constrainedWidth="true" to its constraints are enforced when the width is set to wrap_content. It should look like this:

    <TextView
            android:id="@+id/foo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Foo"
            app:layout_constrainedWidth="true"
            app:layout_constraintHorizontal_bias="0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toStartOf="@id/progress1"
            app:layout_constraintTop_toTopOf="parent" />
    

    It will cause the text to wrap to the next line when it reaches the progress bar. You can add ellipsis or limit the TextView to have the maximum of 1 line if you don't want the text to wrap.

    Alternatively, you can just set the left TextView's width to 0 so it takes all available space to the left of the progress bar.