raenardev
07/10/2021, 4:31 PMfillMaxSize
modifier, while box also has verticalScroll
.
As soon as box has scroll, its child column can no longer be at max size. Is this expected? Feels like a bug to me.
Screenshots and code in threadraenardev
07/10/2021, 4:31 PM@Composable
fun TestComposable() {
val scrollState = rememberScrollState()
Column(
Modifier
.fillMaxSize()
.background(Color(0xFFA05151))
) {
Box(
Modifier
.fillMaxSize()
.verticalScroll(scrollState)
.background(Color(0xFF1178AF))
) {
Column(
Modifier
.fillMaxSize()
.background(Color(0xFF48AF11))
) {
Text(text = "hello", color = Color(0xFFFFFFFF))
}
}
}
}
raenardev
07/10/2021, 4:32 PMverticalScroll
raenardev
07/10/2021, 4:32 PMAdam Powell
07/10/2021, 4:39 PMraenardev
07/10/2021, 6:17 PMandroid:fillViewport
Here, i could use BoxWithConstraints
, but maybe there is another way?
@Composable
fun TestComposable() {
val scrollState = rememberScrollState()
Column(
Modifier
.fillMaxSize()
.background(Color(0xFFA05151))
) {
BoxWithConstraints {
val boxMaxHeight = maxHeight
Box(
Modifier
.fillMaxSize()
.verticalScroll(scrollState)
.background(Color(0xFF1178AF))
) {
Column(
Modifier
.defaultMinSize(minHeight = boxMaxHeight)
.fillMaxWidth()
.background(Color(0xFF48AF11))
) {
Text(text = "hello", color = Color(0xFFFFFFFF))
}
}
}
}
}
Adam Powell
07/10/2021, 7:20 PMBoxWithConstraints
is very expensive for this sort of use case, all you're looking to do is propagate the viewport constraints to a lower child during measurement, there's no need to return to composition or defer composition for that, which BoxWithConstraints
will do.Adam Powell
07/10/2021, 7:21 PMvar constraints by remember { mutableStateOf(Constraints()) }
Column(
Modifier
.fillMaxSize()
.onMeasureConstraints { constraints = it }
.verticalScroll(rememberScrollState())
) {
Box(
Modifier
.fillMaxWidth()
.constrainSize { constraints }
.background(Color.Blue)
)
Box(Modifier.fillMaxWidth().height(100.dp).background(Color.Green))
}
// elsewhere at the top level...
fun Modifier.onMeasureConstraints(
block: (Constraints) -> Unit
) = layout { measurable, constraints ->
// record the constraints *before* measuring so that they're available during recursive measurement
block(constraints)
val placeable = measurable.measure(constraints)
layout(placeable.width, placeable.height) {
placeable.place(0, 0)
}
}
fun Modifier.constrainSize(
getConstraints: () -> Constraints
) = layout { measurable, constraints ->
val placeable = measurable.measure(constraints.constrain(getConstraints()))
layout(placeable.width, placeable.height) {
placeable.place(0, 0)
}
}
Adam Powell
07/10/2021, 7:21 PMAdam Powell
07/10/2021, 7:22 PMfillMaxHeight(0.9)
to make sure that there's always a bit of scrollable content still visible as opposed to filling the entire viewport, etc.Adam Powell
07/10/2021, 7:23 PMconstrainSize
defines getConstraints
as a function and not a raw value, since invoking that function performs a state read of the previously written constraints, invalidating the measurement of the `constrainSize`'d element when the input constraints change, but without invalidating the composition that created itraenardev
07/10/2021, 7:57 PMconstraints
state needs to be invalidated (which in this example starts with Column
) since there no other way to trigger change, but if there is a function inside layout
that reads it, then that invalidation scope is just that layout
block - so only Box
and its children will get invalidated?Adam Powell
07/10/2021, 9:11 PMraenardev
07/11/2021, 10:57 AM