Jetpack Compose: Nested weight in custom component

1.5k views Asked by At

Say that I have a button that expands when tapped the first time to reveal text, and performs an action on the second tap--thus acting as a sort of confirmation before performing the action.

@Compose
fun ExpandingConfirmButton(onConfirm: () -> Unit) {
    // expanded state of the button
    val (expanded, setExpanded) = remember { mutableStateOf(false) }
    // animating weight. make the button larger when it is tapped once
    val weight = animate(if (expanded) 10F else 2F)

    Button(onClick = {
        // only fire the action after two taps
        if(expanded) {
            onConfirm()
        }
        setExpanded(!expanded)    
    }) {
        Icon(Icons.Dfault.Delete)
        // only show the text if the button has already been clicked once,
        //  otherwise just show the icon
        if(expanded) {
            Text(text = "Delete", softWrap = false)
        }
    }
}

And I would use that button like so:

@Composable
fun PersonList(people: List<Person>) {
    // some database service exposed via an ambient
    val dataService = DataService.current

    LazyColumnFor(items = people) {
        Row() {
            Text(text = it.firstName, modifier = Modifier.weight(10F))
            // on the first tap, the button should take up half of the row
            ExpandingConfirmButton(onConfirm = { dataService.deletePerson(it) })
        }
    }
}

Here's what it looks like when it worked, before I made it into a separate component.

This all seems pretty straight-forward. Indeed, before I had split the ExpandingConfirmButton into it's own component and instead had the Button() it wraps directly in my PersonList component, it worked flawlessly.

However, it seems that the Row doesn't quite know what to do with the button when the weight changes when it is inside it's own component. The text inside the button displays, but the size does not change. Does this have to do with the Row's RowScope not getting utilized by the Modifier on the Button component inside ExpandingConfirmButton? If so, how do I go about using it?

1

There are 1 answers

0
foxtrotuniform6969 On BEST ANSWER

What I ended up doing is basically just using the .animateContentSize() modifier.

@Compose
fun ExpandingConfirmButton(onConfirm: () -> Unit) {
    // expanded state of the button
    val (expanded, setExpanded) = remember { mutableStateOf(false) }

    Button(
        modifier = Modifier.animateContentSize(), // do this
        onClick = {
        // only fire the action after two taps
        if(expanded) {
            onConfirm()
        }
        setExpanded(!expanded)    
    }) {
        Icon(Icons.Default.Delete)
        // only show the text if the button has already been clicked once,
        //  otherwise just show the icon
        if(expanded) {
            Text(text = "Delete", softWrap = false)
        }
    }
}

It really is just that easy. No messing with manual widths, weights, or anything like that.