1

I want to have a horizontal alignment of four buttons with these conditions:

  • their texts are 25%, 50%, 75%, 100% (so the last one will be wider)
  • they should have same width
  • they should spread the through the remaining space

Is it possible to achieve this using ConstraintLayout?

To demonstrate what I exactly want, take a look at current state of my layout (which is ok): enter image description here

The buttons currently are set to have a width of 25 percent of the parent and there's a static margin between them (implemented using a LinearLayout). What is the problem? It's possible in small screens that the margin cause the last button to be truncated (like the image below), or in large screens the buttons be so large.

enter image description here

So I want the spread behavior of ConstraintLayout besides width of the last button be wrap_content and width of other buttons be set equal to the last button.

momvart
  • 1,737
  • 1
  • 20
  • 32
  • if you want to use same in linearlayout specify dimentions in dimen.xml under xdpi,xhdpi,xxhdpi and have it category specific size it will not break in diffrennt devices – Neha Rathore May 18 '20 at 10:01
  • @NehaRathore yeah this could be a way of doing it but I prefer a way that is more dynamic and can take advantage of `wrap_content` – momvart May 18 '20 at 10:42
  • 1
    [Here](https://stackoverflow.com/a/59061950/6287910) is one solution to question that is asked many times on Stack Overflow. Keep an eye out on new releases of _ConstraintLayout_ in case there is an official solution. – Cheticamp May 18 '20 at 15:59
  • @Cheticamp thanks. it seems that this is the cleanest way of achieving this. I could set your solution as answer if you posted it. – momvart May 18 '20 at 16:42
  • Thanks for the offer, but it's already an answer. – Cheticamp May 18 '20 at 16:44

3 Answers3

2

Thanks to @cheticamp and his answer provided here, the best way of achieving the desired behavior would be writing a simple ConstraintHelper which sets width of all the children to the maximum among them.

class MaxWidthConstraint @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {
    override fun updatePostMeasure(container: ConstraintLayout) {
        val maxWidth =
            referencedIds.asSequence().map { container.getViewById(it) }
                .map { container.getViewWidget(it) }
                .map { it.width }
                .max() ?: 0
        referencedIds.asSequence().map { container.getViewById(it) }
            .map { container.getViewWidget(it) }
            .forEach { it.width = maxWidth }
    }
}

So the layout code would be:

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:ignore="HardcodedText">

    <Button
        android:id="@+id/btn_25"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="25%"
        android:textAlignment="center"
        app:layout_constraintEnd_toStartOf="@id/btn_50"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_50"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="50%"
        app:layout_constraintEnd_toStartOf="@id/btn_75"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintStart_toEndOf="@id/btn_25"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_75"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="75%"
        app:layout_constraintEnd_toStartOf="@id/btn_100"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintStart_toEndOf="@id/btn_50"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_100"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="100%"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_chainStyle="spread_inside"
        app:layout_constraintStart_toEndOf="@id/btn_75"
        app:layout_constraintTop_toTopOf="parent" />

    <com.myapplication.widgets.MaxWidthConstraint
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:constraint_referenced_ids="btn_25,btn_50,btn_75,btn_100"
        tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
momvart
  • 1,737
  • 1
  • 20
  • 32
0

So this is what i came up with:

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

    <Button
        android:id="@+id/tv_25"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="16dp"
        android:text="25%"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/tv_50"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/tv_50"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="16dp"
        android:text="50%"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintLeft_toRightOf="@id/tv_25"
        app:layout_constraintRight_toLeftOf="@id/tv_75"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/tv_75"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="16dp"
        android:text="75%"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintLeft_toRightOf="@id/tv_50"
        app:layout_constraintRight_toLeftOf="@id/tv_100"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/tv_100"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:text="100%"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintLeft_toRightOf="@id/tv_75"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

enter image description here

Explanation: I've used app:layout_constraintHorizontal_chainStyle="spread".Using chain takes the margin into account while spreading the views evenly.

Tayyab Mazhar
  • 1,560
  • 10
  • 26
  • Thank for your answer Tayyab. But it still has the same problem of static 16dp of margin. I want to margin be reduced or disappeared when there's not enough space. – momvart May 18 '20 at 10:47
  • That'll require some java coding. You'd have to measure screen width and width of views, then set the margin accordingly. I'll see if i can try. – Tayyab Mazhar May 18 '20 at 10:53
  • Yeah, but I was looking for a way (if exists) with XML and constraint layout. If not I should just set width of the other buttons equal to the last one during runtime – momvart May 18 '20 at 11:01
  • You can't make margin dynamic within XML. – Tayyab Mazhar May 18 '20 at 11:03
0

Using chain style spread might be you got your expected layout.

enter image description here

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

    <Button
        android:id="@+id/btn_25"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/entercode_default"
        android:text="25%"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btn_50"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_50"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/entercode_default"
        android:text="50%"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btn_75"
        app:layout_constraintStart_toEndOf="@+id/btn_25"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_75"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/entercode_default"
        android:text="75%"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btn_100"
        app:layout_constraintStart_toEndOf="@+id/btn_50"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_100"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/entercode_default"
        android:text="100%"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btn_75"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Shweta Chauhan
  • 6,739
  • 6
  • 37
  • 57