'Problem when trying to wrap chains of width-constrained views

I'm trying to implement a very common portrait/landscape layout flexibility approach using newly-introduced ConstraintLayout Flow helper in chain wrapping mode.

I want to position two views automatically in line for landscape orientation and one under another for portrait, e.g. wrap to fit. I can achieve this already with FlexboxLayout but I prefer a flat structure and performance of ConstraintLayout.

<androidx.constraintlayout.widget.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"
    android:background="#B0B0B0">

    <androidx.constraintlayout.helper.widget.Flow
        android:layout_width="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:flow_wrapMode="chain"
        app:constraint_referenced_ids="view1,view2"
        android:layout_height="0dp" />

    <View
        android:id="@+id/view1"
        android:layout_width="0dp"
        android:layout_height="200dp"
        app:layout_constraintDimensionRatio="1:1"
        android:background="#808080"
        tools:ignore="MissingConstraints">
    </View>

    <View
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:layout_height="200dp"
        app:layout_constraintDimensionRatio="1:1"
        android:background="#E0E0E0"
        tools:ignore="MissingConstraints">
    </View>

</androidx.constraintlayout.widget.ConstraintLayout>

I get this for landscape, and it's fine:

landscape

But I get this for portrait:

portrait, unexpected

If I set fixed width 200dp (or wrap_content for other cases also ok), everything works as expected:

portrait, expected

Since ConstraintLayout 2.0.0 is in beta and recent changelog reports about fixes in wrap support, I suppose that it is a bug.

But maybe I'm missing something? Thank you



Solution 1:[1]

The default orientation of the Flow widget is horizontal. Therefore, it needs to know layout_width values of its referenced widgets.

It seems that Flow can't calculate these values based on the app:layout_constraintDimensionRatio (at least, not in the Tools preview.. I did not test how it behaves at runtime).

In your code, you can swap the layout_width and layout_height values to achieve your desired results.

<androidx.constraintlayout.widget.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"
    tools:ignore="MissingConstraints">

    <androidx.constraintlayout.helper.widget.Flow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:constraint_referenced_ids="view_red, view_blue"
        app:flow_wrapMode="chain"/>

    <View
        android:id="@+id/view_red"
        android:layout_width="300dp"
        android:layout_height="0dp"
        android:background="#C62828"
        app:layout_constraintDimensionRatio="1:1"/>

    <View
        android:id="@+id/view_blue"
        android:layout_width="300dp"
        android:layout_height="0dp"
        android:background="#1565C0"
        app:layout_constraintDimensionRatio="1:1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

However, keep in mind that chaining/wrapping only occurs if the referenced widgets do not fit in the specified orientation (default: horizontal). In my code, I had to set layout_width to 300dp for chaining to happen in the Tools preview.

So, if you're running on a tablet, for example, using this method will not guarantee that your widgets will be positioned vertically because there is more horizontal space to accommodate the widgets.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1