I have a layout problem that I though ConstraintLa...
# compose
t
I have a layout problem that I though ConstraintLayout could help me with. Now I'm not as sure. My current attempts result in the graphic. Hanging the label and button to the leftCenter and rightCenter respectively is straightforward. I want the text box to fill most of the area in between. But I want it to remain centered. So just linking the left to the label right and the right to the button left, isn't quite right. No matter what I do though, the text box ends up only being as big as the text inside it. I want it, as an area to fill the whole (centered bound) area, not just how many characters it is (have to expand the image to the see the name/button to the left and right)
What I've tried/learned/observed: • setting the text width to fillMaxWidth seems to override any constraints I put on it, it just goes full width, whether done before or after the constrainAs • If I use
Copy code
.constrainAs(textRef) {
    absoluteLeft.linkTo(labelRef.absoluteRight)
    absoluteRight.linkTo(buttonRef.absoluteLeft)
    centerTo(parent)
}
it doesn't seem to center, just centers between the uneven width edge widgets
b
Subcompose layout is probably your friend here. Had to do something for a client for a tablet layout to keep the search bar centered for multi window support
s
Something like:
Copy code
Row {
    Icon()
    Box(Modifier.weight(1f)) {
        Text(...)
    }
    Icon()
}
Oh, wait, you want to center in the parent bounds and not between icons Probably the best bet is to write a custom layout here that places the icons to the side and text in the middle (no need for subcompose layout)
1
b
You know what I think that’s what we ended up with now that you mention it
t
But while I want to center, I want to make it be as wide as it can be without overwriting either of them. So am I correct that Constraints can't do that? (I know I could do this pretty easy in the iOS constraint system, but I've learned that comparing the two is Apples and Avacadoes)
b
You could easily achieve this with a custom layout, I wouldn't worry about trying to work out the constraints. https://developer.android.com/jetpack/compose/layouts/custom
t
YEah, just tried that out. Didn't have so much luck. Missing pieces of the puzzle still I guess.
I thought something like:
Copy code
Layout(content = {
    SettingsLabel(
       text_id = R.string.mcHostSettingsCard_name
    )
    Text(
       text = mc.name ?: "", ..., textAlign = TextAlign.Center
    )
    CircleButton(icon_id = R.drawable.screwdriver_in_circle_mask, onClick = { isEditing = NOT(isEditing) })
}, modifier = modifier) { measurables, constraints ->
    val (labelPlaceable, textPlaceable, buttonPlaceable) = measurables.map { measurable -> measurable.measure(constraints) }
    val maxInset = maxOf(labelPlaceable.width, buttonPlaceable.width)
    layout(constraints.maxWidth, constraints.maxHeight) {
       val width = constraints.maxWidth
       val height = constraints.maxHeight
       labelPlaceable.place(0, (height - labelPlaceable.height) / 2)
       textPlaceable.place(maxInset, (height - textPlaceable.height) / 2)
       buttonPlaceable.place(width - buttonPlaceable.width, (height - buttonPlaceable.height) / 2)
    }
}
would get me in the ballpark at least. But logging some of the points, my maxInset ends up being the screen width. I'm interested in the intrinsic widths (I think?) of the first and last placeables. But getting something very different. It's not clear to me how one sets the width of the middle placeable either, seems I can place it, but not adjust its width 😕
OK... figured out I need to do constraints.copy(minWidth = 0) in the measure argument. That makes sense to me. Still not clear how I can then adjust the length of the textPlaceable to fill the whole area
This was the MeasurePolicy I ended up using (which worked). Any feedback on whether I did this rightish?
Copy code
{ (labelMeasure, textMeasure, buttonMeasure), constraints ->
    val labelPlacer = labelMeasure.measure(constraints.copy(minWidth = 0))
    val buttonPlacer = buttonMeasure.measure(constraints.copy(minWidth = 0))
    val maxInset = maxOf(labelPlacer.measuredWidth, buttonPlacer.measuredWidth)
    val textWidth = constraints.maxWidth - maxInset - maxInset
    val textPlacer = textMeasure.measure(constraints.copy(minWidth = textWidth))
    val maxHeight = listOf(labelPlacer, textPlacer, buttonPlacer).maxOf { p -> p.height }
    layout(constraints.maxWidth, maxHeight) {
       val width = constraints.maxWidth
       labelPlacer.place(0, (maxHeight - labelPlacer.height) / 2)
       textPlacer.place(maxInset, (maxHeight - textPlacer.height) / 2)
       buttonPlacer.place(width - buttonPlacer.width, (maxHeight - buttonPlacer.height) / 2)
    }