In jetpack Compose dimensions of Composable or child Composables are set using Constraints which is set of dimensions and flags for being bounded or finite. And be Modifier.requiredX are used for forcing size but it can easily break your layout if the constraints are not in limit of parents.
Difference between widthIn
and requiredWidthIn
is first one abides size modifiers before it or max parent dimensions while latter can force constraints.
/**
* Create a [Constraints]. [minWidth] and [minHeight] must be positive and
* [maxWidth] and [maxHeight] must be greater than or equal to [minWidth] and [minHeight],
* respectively, or [Infinity][Constraints.Infinity].
*/
@Stable
fun Constraints(
minWidth: Int = 0,
maxWidth: Int = Constraints.Infinity,
minHeight: Int = 0,
maxHeight: Int = Constraints.Infinity
): Constraints {
require(maxWidth >= minWidth) {
"maxWidth($maxWidth) must be >= than minWidth($minWidth)"
}
require(maxHeight >= minHeight) {
"maxHeight($maxHeight) must be >= than minHeight($minHeight)"
}
require(minWidth >= 0 && minHeight >= 0) {
"minWidth($minWidth) and minHeight($minHeight) must be >= 0"
}
return Constraints.createConstraints(minWidth, maxWidth, minHeight, maxHeight)
}
based on Constraints
during measurement width and height are assigned to Composables as Placeable
s.
In the sample below when TextField doesn't have parent with fixed size it grows till max width. If fixed size that is smaller than TextField is set when Modifier.widthIn() is used TextField is set to parent width while Modifier.requiredWidthIn() jumps out of parent as (TextField size - parent size)/2

@Composable
private fun TextFieldSamples() {
Column(
modifier = Modifier
.padding(20.dp).border(2.dp, Color.Cyan)
) {
var text1 by remember { mutableStateOf("") }
Column(modifier = Modifier) {
TextField(
modifier = Modifier
.border(2.dp, Color.Green)
.widthIn(56.dp),
value = text1,
onValueChange = { text1 = it }
)
TextField(
modifier = Modifier
.border(2.dp, Color.Red)
.requiredWidthIn(56.dp),
value = text1, onValueChange = { text1 = it })
}
Spacer(modifier = Modifier.height(30.dp))
var text2 by remember { mutableStateOf("") }
Column(modifier = Modifier.width(50.dp)) {
TextField(
modifier = Modifier
.border(2.dp, Color.Green)
.widthIn(56.dp),
value = text2, onValueChange = { text2 = it })
TextField(
modifier = Modifier
.border(2.dp, Color.Red)
.requiredWidthIn(56.dp),
value = text2, onValueChange = { text2 = it })
}
}
}
Size Modifiers
Modifier.width/height()
Returns fixed Constraints or one with equal minWidth/Height and maxWidth/Height.
So Child Composables are limited to this Constraints
Modifier.fillmaxWidth/Height(fraction)
Covers fraction of space that is available from parent's max constraints
Modifier.width/heightIn(min)
Reserves minimum width/height as this value so child Composables can be measured using this dimension. Children can be lower than this value or greater until max width/height
Modifier.width/heightIn(max)
This is the max width/height children can be measured with. Children Composables cannot be measured with dimension bigger than max width/height.
@Composable
private fun ConstraintsSample1() {
Text(text = "Fixed Size")
BoxWithConstraints(modifier = Modifier
.size(100.dp)
.border(3.dp, Color.Green)) {
Box(modifier = Modifier
.size(50.dp)
.background(Color.Red))
}
Spacer(modifier=Modifier.height(10.dp))
BoxWithConstraints(modifier = Modifier
.size(100.dp)
.border(3.dp, Color.Green)) {
Box(modifier = Modifier
.size(150.dp)
.background(Color.Red))
}
Text(text = "widthIn(min)")
BoxWithConstraints(modifier = Modifier
.widthIn(min = 100.dp)
.border(3.dp, Color.Green)) {
Box(modifier = Modifier
.size(50.dp)
.background(Color.Red))
}
Spacer(modifier=Modifier.height(10.dp))
BoxWithConstraints(modifier = Modifier
.widthIn(min = 100.dp)
.border(3.dp, Color.Green)) {
Box(modifier = Modifier
.size(150.dp)
.background(Color.Red))
}
Text(text = "widthIn(max)")
BoxWithConstraints(modifier = Modifier
.widthIn(max = 100.dp)
.border(3.dp, Color.Green)) {
Box(modifier = Modifier
.size(50.dp)
.background(Color.Red))
}
Spacer(modifier=Modifier.height(10.dp))
BoxWithConstraints(modifier = Modifier
.widthIn(max = 100.dp)
.border(3.dp, Color.Green)) {
Box(modifier = Modifier
.size(150.dp)
.background(Color.Red))
}
}
Modifier.requiredWidth/Height()
Constrain the width/height of the content to be between `minDp` and `maxDp`. If the content chooses a size that does not satisfy the incoming Constraints, the parent layout will be reported a size coerced in the Constraints, and the position of the content will be automatically offset to be centered on the space assigned to the child by the parent layout under the assumption that Constraints were respected.
For instance when you set Modifier.size(50.dp).size(100.dp)
first size modifier is applied however if you user requiredIn
Modifier.size(50.dp).requiredSizeIn(100.dp)
100.dp is forced but layout is placed as half of difference between 2 dimensions
@Composable
private fun ConstraintsSample2() {
Column(modifier = Modifier
.fillMaxSize()
.padding(30.dp)
.border(4.dp, Color.Cyan)) {
Text(text = "Chaining size modifiers")
Box(modifier = Modifier
.size(50.dp)
.background(Color.Yellow))
Box(modifier = Modifier
.size(50.dp)
.size(100.dp)
.background(Color.Red))
Box(modifier = Modifier
.size(50.dp)
.requiredSizeIn(100.dp)
.background(Color.Green))
Text(text = "widthIn(max)")
BoxWithConstraints(
modifier = Modifier
.width(100.dp)
.border(3.dp, Color.Green)
) {
Box(
modifier = Modifier
.requiredWidthIn(min = 20.dp, max = 50.dp)
.height(50.dp)
.background(Color.Red)
)
}
Spacer(modifier = Modifier.height(10.dp))
BoxWithConstraints(
modifier = Modifier
.width(100.dp)
.border(3.dp, Color.Green)
) {
Box(
modifier = Modifier
.requiredWidthIn(min = 150.dp, max = 200.dp)
.height(50.dp)
.background(Color.Red)
)
}
}
}
Constraints
Constraints change based on size modifiers, vertical/horizontal scroll or how parent chooses to limit or want to use min or max dimension.
Max device on my device width is 1080px, and 200.dp is 525px in the samples below. And used verticalScroll that's why height is measured with Constraints.Infinity
@Composable
fun ConstraintsSample3() {
Column(modifier = Modifier) {
Text(text = "No Dimension Modifier")
BoxWithConstraints(modifier = Modifier.background(Brown400)) {
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val minWidth = constraints.minWidth
val maxWidth = constraints.maxWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val minHeight = constraints.minHeight
val maxHeight = constraints.maxHeight
Text(
"minWidth: $minWidth, maxWidth: $maxWidth\n" +
"hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
"minHeight: $minHeight, maxHeight: $maxHeight\n" +
"hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
color = Color.White
)
}
Spacer(modifier = Modifier.height(10.dp))
Text(text = "FillMaxWidth and 200.dp Height")
BoxWithConstraints(
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
.background(Red400)
) {
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val minWidth = constraints.minWidth
val maxWidth = constraints.maxWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val minHeight = constraints.minHeight
val maxHeight = constraints.maxHeight
Text(
"minWidth: $minWidth, maxWidth: $maxWidth\n" +
"hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
"minHeight: $minHeight, maxHeight: $maxHeight\n" +
"hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
color = Color.White
)
}
Spacer(modifier = Modifier.height(10.dp))
Text(text = "wrapContentSize()")
BoxWithConstraints(
modifier = Modifier
.wrapContentSize()
.background(Orange400)
) {
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val minWidth = constraints.minWidth
val maxWidth = constraints.maxWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val minHeight = constraints.minHeight
val maxHeight = constraints.maxHeight
Text(
"minWidth: $minWidth, maxWidth: $maxWidth\n" +
"hasBoundedWidth: $hasBoundedWidth\n" +
"hasFixedWidth: $hasFixedWidth\n" +
"minHeight: $minHeight\n" +
"maxHeight: $maxHeight\n" +
"hasBoundedHeight: $hasBoundedHeight\n" +
"hasFixedHeight: $hasFixedHeight",
color = Color.White
)
}
Spacer(modifier = Modifier.height(10.dp))
Text(text = "200.dp Width and Height")
BoxWithConstraints(
modifier = Modifier
.width(200.dp)
.height(200.dp)
.background(Green400)
) {
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val minWidth = constraints.minWidth
val maxWidth = constraints.maxWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val minHeight = constraints.minHeight
val maxHeight = constraints.maxHeight
Text(
"minWidth: $minWidth, maxWidth: $maxWidth\n" +
"hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
"minHeight: $minHeight, maxHeight: $maxHeight\n" +
"hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
color = Color.White
)
}
}
}
@Composable
private fun BoxWithConstraintsSample4() {
Text(text = "200.dp WidthIn(min) and HeightIn(min)")
BoxWithConstraints(
modifier = Modifier
.widthIn(min = 200.dp)
.heightIn(200.dp)
.background(Blue400)
) {
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val minWidth = constraints.minWidth
val maxWidth = constraints.maxWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val minHeight = constraints.minHeight
val maxHeight = constraints.maxHeight
Text(
"minWidth: $minWidth, maxWidth: $maxWidth\n" +
"hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
"minHeight: $minHeight, maxHeight: $maxHeight\n" +
"hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
color = Color.White
)
}
Text(text = "200.dp requiredWidth(min) and requiredHeight(min)")
BoxWithConstraints(
modifier = Modifier
.requiredWidthIn(min = 200.dp)
.requiredHeightIn(200.dp)
.background(Pink400)
) {
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val minWidth = constraints.minWidth
val maxWidth = constraints.maxWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val minHeight = constraints.minHeight
val maxHeight = constraints.maxHeight
Text(
"minWidth: $minWidth, maxWidth: $maxWidth\n" +
"hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
"minHeight: $minHeight, maxHeight: $maxHeight\n" +
"hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
color = Color.White
)
}
Text(text = "200.dp defaultMinSize()")
BoxWithConstraints(
modifier = Modifier
.defaultMinSize(200.dp)
.background(Pink400)
) {
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val minWidth = constraints.minWidth
val maxWidth = constraints.maxWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val minHeight = constraints.minHeight
val maxHeight = constraints.maxHeight
Text(
"minWidth: $minWidth, maxWidth: $maxWidth\n" +
"hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
"minHeight: $minHeight, maxHeight: $maxHeight\n" +
"hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
color = Color.White
)
}
Text(text = "200.dp WidthIn(max)")
BoxWithConstraints(
modifier = Modifier
.widthIn(max = 200.dp)
.background(Purple400)
) {
val hasBoundedWidth = constraints.hasBoundedWidth
val hasFixedWidth = constraints.hasFixedWidth
val minWidth = constraints.minWidth
val maxWidth = constraints.maxWidth
val hasBoundedHeight = constraints.hasBoundedHeight
val hasFixedHeight = constraints.hasFixedHeight
val minHeight = constraints.minHeight
val maxHeight = constraints.maxHeight
Text(
"minWidth: $minWidth, maxWidth: $maxWidth\n" +
"hasBoundedWidth: $hasBoundedWidth, hasFixedWidth: $hasFixedWidth\n" +
"minHeight: $minHeight, maxHeight: $maxHeight\n" +
"hasBoundedHeight: $hasBoundedHeight, hasFixedHeight: $hasFixedHeight",
color = Color.White
)
}
}