androidandroid-constraintlayoutconstraint-layout-chains

Create vertical chain from multiple horizontal chains with flat view hierarchy ConstraintLayout


I'm trying to take multiple horizontally-chained Buttons and TextViews and chain them vertically as sets of views, but still maintain a flat view hierarchy. Here is my initial layout and code:

Initial Layout

<?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:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btnTopLeft"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#eeeeee"
        app:layout_constraintBottom_toTopOf="@+id/lblTopLeft"
        app:layout_constraintEnd_toStartOf="@+id/btnTopRight"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="1"
        tools:textSize="42sp" />

    <TextView
        android:id="@+id/lblTopLeft"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintBottom_toTopOf="@+id/btnMiddleLeft"
        app:layout_constraintEnd_toEndOf="@id/btnTopLeft"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@id/btnTopLeft"
        app:layout_constraintTop_toBottomOf="@+id/btnTopLeft"
        tools:text="Button 1" />

    <Button
        android:id="@+id/btnTopRight"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#dddddd"
        app:layout_constraintBottom_toTopOf="@+id/lblTopRight"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btnTopLeft"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="2"
        tools:textSize="42sp" />

    <TextView
        android:id="@+id/lblTopRight"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintBottom_toTopOf="@+id/btnMiddleRight"
        app:layout_constraintEnd_toEndOf="@id/btnTopRight"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@id/btnTopRight"
        app:layout_constraintTop_toBottomOf="@+id/btnTopRight"
        tools:text="Button 2" />

    <Button
        android:id="@+id/btnMiddleLeft"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#cccccc"
        app:layout_constraintBottom_toTopOf="@+id/lblMiddleLeft"
        app:layout_constraintEnd_toStartOf="@+id/btnMiddleRight"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/lblTopLeft"
        tools:text="3"
        tools:textSize="42sp" />

    <TextView
        android:id="@+id/lblMiddleLeft"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintBottom_toTopOf="@+id/btnBottomLeft"
        app:layout_constraintEnd_toEndOf="@id/btnMiddleLeft"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@id/btnMiddleLeft"
        app:layout_constraintTop_toBottomOf="@+id/btnMiddleLeft"
        tools:text="Button 3" />

    <Button
        android:id="@+id/btnMiddleRight"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#bbbbbb"
        app:layout_constraintBottom_toTopOf="@+id/lblMiddleRight"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btnMiddleLeft"
        app:layout_constraintTop_toBottomOf="@+id/lblTopRight"
        tools:text="4"
        tools:textSize="42sp" />

    <TextView
        android:id="@+id/lblMiddleRight"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintBottom_toTopOf="@+id/btnBottomRight"
        app:layout_constraintEnd_toEndOf="@id/btnMiddleRight"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@id/btnMiddleRight"
        app:layout_constraintTop_toBottomOf="@+id/btnMiddleRight"
        tools:text="Button 4" />

    <Button
        android:id="@+id/btnBottomLeft"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#aaaaaa"
        app:layout_constraintBottom_toTopOf="@+id/lblBottomLeft"
        app:layout_constraintEnd_toStartOf="@+id/btnBottomRight"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/lblMiddleLeft"
        tools:text="5"
        tools:textSize="42sp" />

    <TextView
        android:id="@+id/lblBottomLeft"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@id/btnBottomLeft"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@id/btnBottomLeft"
        app:layout_constraintTop_toBottomOf="@+id/btnBottomLeft"
        tools:text="Button 5" />

    <Button
        android:id="@+id/btnBottomRight"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#999999"
        app:layout_constraintBottom_toTopOf="@+id/lblBottomRight"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btnBottomLeft"
        app:layout_constraintTop_toBottomOf="@+id/lblMiddleRight"
        tools:text="6"
        tools:textSize="42sp" />

    <TextView
        android:id="@+id/lblBottomRight"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="@id/btnBottomRight"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@id/btnBottomRight"
        app:layout_constraintTop_toBottomOf="@+id/btnBottomRight"
        tools:text="Button 6" />

</android.support.constraint.ConstraintLayout>

When I set the visibility of a Button and its TextView, I would like for the button on the same row to fill the remaining space, but I want the buttons below or above it to remain in the same place until both buttons on the row have been hidden. Once both buttons on the same row have been hidden, then I would like for the remaining buttons to fill the remaining space. For example, here is what I want the layout to look like when I hide Button and TextView 3:

Correct Layout

But currently if I hide Button and TextView 3, here is what currently happens:

Incorrect Layout

This is expected behavior based on my current code, but I'm looking for a way to prevent the vertical chain from collapsing down until button 4 has also been hidden. Once button 4 is hidden, this is the desired result:

Correct Layout 2

I've played around with Barriers, but placing a barrier at any point seems to cause complications with the dynamic heights of the buttons because it breaks the vertical chain. Can anyone provide some insight on how to achieve this with a flat view hierarchy?


Solution

  • Break up the screen into three vertically chained Views as follows:

    enter image description here

    I have set background colors to make the views more prominent, but they would probably be transparent or set to invisible in the actual implementation.

    Now, add the buttons and labels so they are vertically constrained to the interior of these views. This does break the vertical chains, but the vertical sizing is now controlled by the vertical chains of the underlying views. The buttons and labels are still chained to the sides of the ConstraintLayout.

    enter image description here

    Buttons and labels still resize to the left and right as they did before. Now, however, the button underneath will not expand up until all views in a row are set to "gone."

    enter image description here

    You will need to set the underlying view to "gone" when all buttons and labels in a row are also set to "gone", so you will need to keep track of the status of the buttons and labels in a row.

    Here is the XML:

    activity_main.xml

    <android.support.constraint.ConstraintLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <View
            android:id="@+id/topGroup"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@android:color/holo_green_light"
            app:layout_constraintBottom_toTopOf="@id/centerGroup"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <View
            android:id="@+id/centerGroup"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@android:color/holo_blue_light"
            app:layout_constraintBottom_toTopOf="@id/bottomGroup"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/topGroup" />
    
        <View
            android:id="@+id/bottomGroup"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@android:color/holo_orange_light"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/centerGroup" />
    
        <Button
            android:id="@+id/btnTopLeft"
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="#eeeeee"
            app:layout_constraintBottom_toTopOf="@+id/lblTopLeft"
            app:layout_constraintEnd_toStartOf="@+id/btnTopRight"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/topGroup"
            tools:text="1"
            tools:textSize="42sp" />
    
        <TextView
            android:id="@+id/lblTopLeft"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            app:layout_constraintBottom_toBottomOf="@+id/topGroup"
            app:layout_constraintEnd_toEndOf="@id/btnTopLeft"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="@id/btnTopLeft"
            app:layout_constraintTop_toBottomOf="@+id/btnTopLeft"
            tools:text="Button 1" />
    
        <Button
            android:id="@+id/btnTopRight"
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="#dddddd"
            app:layout_constraintBottom_toTopOf="@+id/lblTopRight"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@+id/btnTopLeft"
            app:layout_constraintTop_toTopOf="@id/topGroup"
            tools:text="2"
            tools:textSize="42sp" />
    
        <TextView
            android:id="@+id/lblTopRight"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            app:layout_constraintBottom_toBottomOf="@+id/topGroup"
            app:layout_constraintEnd_toEndOf="@id/btnTopRight"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="@id/btnTopRight"
            app:layout_constraintTop_toBottomOf="@+id/btnTopRight"
            tools:text="Button 2" />
    
        <Button
            android:id="@+id/btnMiddleLeft"
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="#cccccc"
            app:layout_constraintBottom_toTopOf="@+id/lblMiddleLeft"
            app:layout_constraintEnd_toStartOf="@+id/btnMiddleRight"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/centerGroup"
            tools:text="3"
            tools:textSize="42sp" />
    
        <TextView
            android:id="@+id/lblMiddleLeft"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            app:layout_constraintBottom_toBottomOf="@+id/centerGroup"
            app:layout_constraintEnd_toEndOf="@id/btnMiddleLeft"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="@id/btnMiddleLeft"
            app:layout_constraintTop_toBottomOf="@+id/btnMiddleLeft"
            tools:text="Button 3" />
    
        <Button
            android:id="@+id/btnMiddleRight"
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="#bbbbbb"
            app:layout_constraintBottom_toTopOf="@+id/lblMiddleRight"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@+id/btnMiddleLeft"
            app:layout_constraintTop_toTopOf="@+id/centerGroup"
            tools:text="4"
            tools:textSize="42sp" />
    
        <TextView
            android:id="@+id/lblMiddleRight"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            app:layout_constraintBottom_toBottomOf="@+id/centerGroup"
            app:layout_constraintEnd_toEndOf="@id/btnMiddleRight"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="@id/btnMiddleRight"
            app:layout_constraintTop_toBottomOf="@+id/btnMiddleRight"
            tools:text="Button 4" />
    
        <Button
            android:id="@+id/btnBottomLeft"
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="#aaaaaa"
            app:layout_constraintBottom_toTopOf="@+id/lblBottomLeft"
            app:layout_constraintEnd_toStartOf="@+id/btnBottomRight"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/bottomGroup"
            tools:text="5"
            tools:textSize="42sp" />
    
        <TextView
            android:id="@+id/lblBottomLeft"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            app:layout_constraintBottom_toBottomOf="@id/bottomGroup"
            app:layout_constraintEnd_toEndOf="@id/btnBottomLeft"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="@id/btnBottomLeft"
            app:layout_constraintTop_toBottomOf="@+id/btnBottomLeft"
            tools:text="Button 5" />
    
        <Button
            android:id="@+id/btnBottomRight"
            style="?android:attr/borderlessButtonStyle"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="#999999"
            app:layout_constraintBottom_toTopOf="@+id/lblBottomRight"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toEndOf="@+id/btnBottomLeft"
            app:layout_constraintTop_toTopOf="@+id/bottomGroup"
            tools:text="6"
            tools:textSize="42sp" />
    
        <TextView
            android:id="@+id/lblBottomRight"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            app:layout_constraintBottom_toBottomOf="@id/bottomGroup"
            app:layout_constraintEnd_toEndOf="@id/btnBottomRight"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="@id/btnBottomRight"
            app:layout_constraintTop_toBottomOf="@+id/btnBottomRight"
            tools:text="Button 6" />
    
    </android.support.constraint.ConstraintLayout>