I am confused by what the modifiers fillMaxWidth() and wrapContentWidth() in Jetpack Compose do. I have read through the documentation and looked at their implementations, but I am still not exactly sure how they work (internally).
Here is my understanding of what they do:
fillMaxWidth() sets the width of the element to the maximum width of its parent container. My understanding is that it does so by setting the minimum width and and the maximum width to be equal to the maximum width of the parent.
wrapContentWidth() causes a layout element to be as wide as the element's content.
My questions are:
In case of fillMaxWidth(), is my understanding of what it does internally correct (setting the minimum width and and the maximum width to be equal to the maximum width of the parent)?
In case of wrapContentWidth(), does is causes a layout element to be as wide as the element's content by setting the min and max width of the element to be the width of the content?
Also, what would the following modifier exactly do if I applied it to an element? modifier = Modifier.fillMaxWidth().wrapContentWidth() Wouldn't the wrapContentWidth() just undo what fillMaxWidth did? And what if I switched the order and used modifier = Modifier.wrapContentWidth().fillMaxWidth()?
Thanks for all help.
CodePudding user response:
fillMaxWidth()
will set the min and max width of the composble to the maximum allowed by the container, to fill all the spacewrapContentWidth()
will set the min width to 0 (so ignores a previous min width), and you can do the same with the max width if you set unbounded to true
You can combine them to have some effects, for instance you could use a fillMaxWidth
to set a certain background color, then have a child composable centered in the same container using wrapContentWidth
and wrapContentHeight
, as seen here (I used wrapContentSize
but the same applies to both wrapContentWidth
and wrapContentHeight
)
@Preview(widthDp = 360, heightDp = 360)
@Composable
private fun PreviewMOdifier() {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.Red)
.wrapContentSize(Alignment.Center)
.background(Color.Blue)
) {
Text(
text = "This is the body",
modifier = Modifier
.padding(all = 16.dp)
.background(Color.Yellow)
)
}
}
Edit: here's another example, try removing wrapContentHeight
in the Box
modifier so see how the preview changes
@Preview(heightDp = 360)
@Composable
private fun PreviewThreeBlock() {
PlaygroundTheme {
Surface(
color = MaterialTheme.colorScheme.background
) {
Box(
modifier = Modifier.wrapContentHeight().background(Color.Red)
) {
Text(text = "FooBar")
}
}
}
}
CodePudding user response:
In Jetpack Compose setting size of child or/and container Composables are done using Constraints
coming from size Modifiers, parent or scroll as they return Constraints.Infinity.
Measuring a Composable with parent or modified Constraints determines which size that child Composable will have
You can check out Constraints section of
@Composable
private fun WrapWidthExample() {
Row() {
Surface(
modifier = Modifier
.size(200.dp)
.border(2.dp, Color.Yellow),
onClick = {}) {
Column(
modifier = Modifier
.size(50.dp)
.background(Color.Red, RoundedCornerShape(6.dp))
) {
Box(
modifier = Modifier
.size(50.dp)
.background(Color.Green, RoundedCornerShape(6.dp))
)
}
}
Surface(
modifier = Modifier
.size(200.dp)
.border(2.dp, Color.Yellow),
onClick = {}) {
Column(
modifier = Modifier
.wrapContentWidth()
.background(Color.Red, RoundedCornerShape(6.dp))
) {
Box(
modifier = Modifier
.size(50.dp)
.background(Color.Green, RoundedCornerShape(6.dp))
)
}
}
}
}
Without Modifier.wrapContentWidth()
200.dp(525px in my device) is forced to red Column for measuring Measurable
, but with wrapContentWidth allows that Composable to use its own min Constraints which is 0 because of not assigning any Modifier.
- Allow the content to measure at its desired width without regard for the incoming measurement * [minimum width constraint][Constraints.minWidth], and, if [unbounded] is true, also without * regard for the incoming measurement [maximum width constraint][Constraints.maxWidth]. If * the content's measured size is smaller than the minimum width constraint, [align] * it within that minimum width space. If the content's measured size is larger than the maximum * width constraint (only possible when [unbounded] is true), [align] over the maximum * width space.
And the Constraints what is returned from this Modifier is as
val wrappedConstraints = Constraints(
minWidth = if (direction != Direction.Vertical) 0 else constraints.minWidth,
minHeight = if (direction != Direction.Horizontal) 0 else constraints.minHeight,
maxWidth = if (direction != Direction.Vertical && unbounded) {
Constraints.Infinity
} else {
constraints.maxWidth
},
maxHeight = if (direction != Direction.Horizontal && unbounded) {
Constraints.Infinity
} else {
constraints.maxHeight
}
)
Basically, wrapContentX can be used when parent forces child Composables to use its Constraints, this can be done when you build your custom Layouts for instance or using Surface as above.
- In Jetpack Compose unless you chain Modifier.requiredX first size modifier is applied while the one after it unless there is no padding, size, etc between is ignored. You can check out requiredSize answer in the first link for more details.