Wrap Content in Jetpack Compose
Asked Answered
U

3

17

How to make the parent layout - Box wrap its content in Jetpack compose? The current implementation below fills the entire screen, I only want the Box to wrap around its child - Switch. How do I define wrap content for the Box?

@Composable
fun TestScreen(modifier: Modifier = Modifier) {
    Box(modifier = Modifier.background(Color.Yellow)){
        val switchState = remember { mutableStateOf(true) }
        Switch(
            checked = switchState.value,
            enabled= true,
            onCheckedChange = { switchState.value = it }
        )
    }
}

A Switch inside a Box

Undrape answered 2/12, 2022 at 0:14 Comment(0)
F
6

Box covers entire screen is probably something more sneaky because of Surface with Modifier.fillMaxSize() updates minimum Constraints of TestScreen because it is direct descendent of Surface.

Surface is a Box with propagateMinConstraints: Boolean = true which forces minimum width and height to its direct descendent. This answer explains with examples how it works.

Your Composable is actually as this when parent is not Surface as i mentioned above.

Surface(
    modifier = Modifier.fillMaxSize()
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(10.dp)
    ) {
        TestScreen()
    }
}

enter image description here

Fushih answered 2/12, 2022 at 4:20 Comment(7)
Is there a way to Specify wrap content to the Box without wrapping it in a Surface+Column?Undrape
There are several ways. First, you don't have to give Modifier.fillMaxSize to your Surface. Having no Modifier returns 0 minWidth and 0 minHeight. You don't have use Surface also. You can do same thing with a Box by applying shape, shadow and other Modifiers. I suggest you to check out Constraints section of the answer i posted to be familiar how size is applied with modifiersFushih
Surface only forces minimum Constraints to direct descendant, other descendants are not effectedFushih
So there is no way to apply WrapContent on a Box as per my question?Undrape
If you use Surface with Modifier.fillMaxSize unfortunately no. propagateMinConstraints = true was a deliberate design. You can google it. I remember seeing and issue why it's set this wayFushih
I don't use any Surface - only a Box as per the sample code in my question.Undrape
Let us continue this discussion in chat.Fushih
S
17

Since you haven't specified on what container/parent composable your posted composable is being called, I can only suggest using Modifier's wrapContentSize.

    Box(
        modifier = Modifier
            .background(Color.Yellow)
            .wrapContentSize() // wrap content height and width
    ){
        val switchState = remember { mutableStateOf(true) }
        Switch(
            checked = switchState.value,
            enabled= true,
            onCheckedChange = { switchState.value = it }
        )
    }

enter image description here

Saboteur answered 2/12, 2022 at 4:7 Comment(7)
If your Composable is not direct child of Surface it already doesn't cover entire screen with or without Modifier.wrapContent. If you set Modifier.wrapContent as in OPs question when Box covers entire screen without any size Modifier which only can happen when it has direct parent is Surface you will see that Modifier.wrapContent or any Modifier you set won't work.Fushih
Thanks for the answer, however it does not work. The wrapContentSize makes the Switch centered in the Box as per this imageUndrape
Ohh, I haven't encountered this yet!, thank you @Fushih again!Saboteur
Actually Doc @Thracian, your'e giving me an idea from an issue I answered recently about the dialog button resizing (the 75% if you have seen it)… thank you again, I upvoted your answer!Saboteur
You are welcome. You can check out my surface answer. I had this Surface issue several times and finally i ceased forgetting :)Fushih
Final quesiton Doc @Thracian, sorry Bullisionist for spamming unrelated topic, do you have an S.O post/answer where you show how to debug placements and measurements?Saboteur
Let us continue this discussion in chat.Fushih
F
6

Box covers entire screen is probably something more sneaky because of Surface with Modifier.fillMaxSize() updates minimum Constraints of TestScreen because it is direct descendent of Surface.

Surface is a Box with propagateMinConstraints: Boolean = true which forces minimum width and height to its direct descendent. This answer explains with examples how it works.

Your Composable is actually as this when parent is not Surface as i mentioned above.

Surface(
    modifier = Modifier.fillMaxSize()
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(10.dp)
    ) {
        TestScreen()
    }
}

enter image description here

Fushih answered 2/12, 2022 at 4:20 Comment(7)
Is there a way to Specify wrap content to the Box without wrapping it in a Surface+Column?Undrape
There are several ways. First, you don't have to give Modifier.fillMaxSize to your Surface. Having no Modifier returns 0 minWidth and 0 minHeight. You don't have use Surface also. You can do same thing with a Box by applying shape, shadow and other Modifiers. I suggest you to check out Constraints section of the answer i posted to be familiar how size is applied with modifiersFushih
Surface only forces minimum Constraints to direct descendant, other descendants are not effectedFushih
So there is no way to apply WrapContent on a Box as per my question?Undrape
If you use Surface with Modifier.fillMaxSize unfortunately no. propagateMinConstraints = true was a deliberate design. You can google it. I remember seeing and issue why it's set this wayFushih
I don't use any Surface - only a Box as per the sample code in my question.Undrape
Let us continue this discussion in chat.Fushih
I
0

Late to the party, but if you add these two,

.width(IntrinsicSize.Min) & .height(IntrinsicSize.Min)

it's as if you added a wrap_content for the width and height

@Composable
fun TestScreen(modifier: Modifier = Modifier) {
    Box(modifier = Modifier
            .background(Color.Yellow)
            .width(IntrinsicSize.Min)
            .height(IntrinsicSize.Min)
    ) {
        val switchState = remember { mutableStateOf(true) }
        Switch(
                checked = switchState.value,
                enabled= true,
                onCheckedChange = { switchState.value = it }
        )
    }
}
Identify answered 5/8 at 18:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.