Skip to content

Instantly share code, notes, and snippets.

@rock3r
Last active July 5, 2023 14:40
Show Gist options
  • Save rock3r/d1e35358ca2f9e1e1846614edfe0919d to your computer and use it in GitHub Desktop.
Save rock3r/d1e35358ca2f9e1e1846614edfe0919d to your computer and use it in GitHub Desktop.
Compose Custom Layout: row of components, all made as wide as the widest one
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* Sebastiano Poggi wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Seb
* ----------------------------------------------------------------------------
*/
package dev.sebastiano.bundel
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import kotlin.math.roundToInt
@Preview
@Composable
fun EqualWidthComponentsRow() {
Surface(Modifier.fillMaxSize()) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(16.dp)
) {
Layout(
modifier = Modifier.border(1.dp, Color.Red),
content = {
Button(onClick = { }) {
Text("First button")
}
Button(onClick = { }) {
Text("Second")
}
}
) { measurables, constraints ->
val hGapWidth = 16.dp.toPx().roundToInt()
val availableButtonWidth = if (constraints.hasBoundedWidth) {
constraints.maxWidth / measurables.size - hGapWidth * (measurables.size - 1)
} else {
Constraints.Infinity
}
val maxIntrinsicWidth = measurables.maxOfOrNull { it.maxIntrinsicWidth(Constraints.Infinity) } ?: error("LOL")
val buttonWidth = maxIntrinsicWidth.coerceAtMost(availableButtonWidth)
val buttonConstraints = Constraints(minWidth = buttonWidth, maxWidth = buttonWidth)
val placeables = measurables.map { it.measure(buttonConstraints) }
val totalWidth = buttonWidth * measurables.size + hGapWidth * (measurables.size - 1)
val height = placeables.maxOfOrNull { it.height } ?: error("LOL")
layout(totalWidth, height) {
var currentX = 0
for (placeable in placeables) {
placeable.placeRelative(currentX, 0)
currentX += buttonWidth + hGapWidth
}
}
}
}
}
}
@rock3r
Copy link
Author

rock3r commented Jun 13, 2023

...and here's how it looks:
preview of the above layout showing two buttons of equal width

@rock3r
Copy link
Author

rock3r commented Jun 14, 2023

Changelog

v1.0.1 (14 Jun 2023)

  • Fixed bug when buttons would take more space than available — thanks Sam!

v1.0.0 (13 Jun 2023)

  • Initial version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment