Reputation: 854
I have a bunch of tiles that I want to distribute horizontally across the screen. They'll be too wide show up on a single row for most devices, so I'd like to use a ConstraintLayout with a Flow helper. I can get that to work.
But I'd like to make sure each tile is the same width. Ideally each tile would be as wide as the required width of the widest tile. What's the right way to make sure that each element in my Flow gets the same width?
(I tried creating a chain and using layout_constraintHorizontal_weight
but that just squeezes every tile into the same row and prevents the Flow from flowing.)
Upvotes: 3
Views: 1899
Reputation: 3156
You can achieve the same width for the children just using Flow
like 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<View
android:id="@+id/view1"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#333" />
<View
android:id="@+id/view2"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#333" />
<View
android:id="@+id/view3"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#333" />
<View
android:id="@+id/view4"
android:layout_width="0dp"
android:layout_height="100dp"
android:background="#333" />
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:constraint_referenced_ids="view1,view2,view3,view4"
app:flow_horizontalGap="8dp"
app:flow_maxElementsWrap="2"
app:flow_verticalGap="8dp"
app:flow_wrapMode="chain"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Preview:
Note: One downside in this solution is, if you have an odd number of elements, then the last element will fill the full width. You can programatically set the last element width at runtime.
Upvotes: 2
Reputation: 854
I ended up adding a ViewTreeObserver that creates a ConstraintSet that sets the size of the children before layout occurs. It isn't pretty, but it does roughly what I want:
final ConstraintLayout statContainer = findViewById(R.id.stat_container);
statContainer.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
try {
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(statContainer);
// Determine a minimum width
int width = 0;
for (int i = 0; i < statContainer.getChildCount(); i++) {
View child = statContainer.getChildAt(i);
if (child instanceof Flow) {
continue;
}
int candidateWidth = child.getMeasuredWidth();
width = Math.max(width, candidateWidth);
}
// Don't allow any child to get too big
int max = statContainer.getWidth() / 3;
width = Math.min(width, max);
// Set that width
for (int i = 0; i < statContainer.getChildCount(); i++) {
View child = statContainer.getChildAt(i);
if (child instanceof Flow) {
continue;
}
constraintSet.constrainWidth(child.getId(), width);
}
constraintSet.applyTo(statContainer);
statContainer.invalidate();
} finally {
statContainer.getViewTreeObserver().removeOnPreDrawListener(this);
}
return false;
}
});
Upvotes: 0