fillMaxWidth
with a value of 0.5f is not working, instead, is wrapping to the content width.
Here is the children, which is inside a LazyRow:
OutlinedButton(
modifier = modifier.fillMaxWidth(0.5f)
How can I use fillMaxWidth() when using scrollable horizontal containers?
I achieved it using this:
OutlinedButton(
modifier = modifier.width(LocalConfiguration.current.screenWidthDp.dp * buttonWidthPercentage)
but I hope there is a better way to do it
The thing is that the fillMaxWidth function makes the element fill the full width of the parent container, while LazyRow has an infinite width. I don’t quite understand what exactly you’re trying to do. If you want the element to take up the entire screen, then instead of LazyRow it’s better to use HorizontalPager.
val myList = remember { mutableStateListOf<MyItem>() }
val pagerState = rememberPagerState(initialPage = 1)
HorizontalPager(
pageCount = myList.size,
state = pagerState
) { page ->
Text(myList[page].name)
}
data class MyItem(
val name: String
)
By default fillMaxWidth
returns minWidth/maxWidth as same value from Constraints
coming from parent or previous Modifier
s. When parent is scrollable or on of the previous Modifiers is scroll maxConstraints becomes Constraints.Infinity
while minWidth is same. maxWidth also can be changed Modifier.layout{}
as well.
Basically Composable measurement range becomes minWidth-Constraints.Infinity with fillMaxWidth. constraints.hasBoundedWidth
checks for infinite maxWidth, and because of that composable can be measured in a range that contains their widths and they are assigned with width as big as their content.
You can read more about Constraints and size modifiers in this link.
The snippet below belongs to node of fillMaxWdith/Height
private class FillNode(
var direction: Direction,
var fraction: Float
) : LayoutModifierNode, Modifier.Node() {
override fun MeasureScope.measure(
measurable: Measurable,
constraints: Constraints
): MeasureResult {
val minWidth: Int
val maxWidth: Int
if (constraints.hasBoundedWidth && direction != Direction.Vertical) {
val width = (constraints.maxWidth * fraction).fastRoundToInt()
.coerceIn(constraints.minWidth, constraints.maxWidth)
minWidth = width
maxWidth = width
} else {
minWidth = constraints.minWidth
maxWidth = constraints.maxWidth
// ... Rest of the node of fillMaxWidth/Height modifier
Your approach is correct, you can also get maxWidth from a BoxWithConstraints, especially useful with paddings, and spaces used by other Composables or Modifiers, if you wrap your LazyRow it. Then using 0.5*maxWidth you can set measurement range, or simply speaking width, for your items in HorizontalRow.
@Preview
@Composable
fun Test() {
BoxWithConstraints(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.border(2.dp, Color.Red)
) {
val itemWidth = maxWidth * .5f
LazyRow {
items(5) {
OutlinedButton(
modifier = Modifier.width(itemWidth),
onClick = {}
) {
Text("Button")
}
}
}
}
}
1
There is a special modifier that works like fillMaxWidth
, but in a LazyRow
, it’s fillParentMaxWidth(fraction: Float)
. From its documentation:
Regular Modifier.fillMaxWidth can’t work inside the scrolling horizontally layouts as the items are measured with Constraints.Infinity as the constraints for the main axis.
Finally solved it by a simpler way:
modifier = modifier.width(LocalConfiguration.current.screenWidthDp.dp * buttonWidthPercentage)
The solution proposed by Jan Bína didn’t work as I’m setting the modifier width in a button but not in a LazyColumn item