Modifier doesn't work when used with .apply
Asked Answered
E

3

12

Why is it that border modifier is not applied when used with .apply { }?

val selected = remember { mutableStateOf(true) }

val selectableModifier = Modifier
    .padding(horizontal = 5.dp, vertical = 8.dp)
    .apply {
    // this changes, but border is not applied
    println("$selected changed") 
    if (selected) {
        border(
            BorderStroke(1.dp, MaterialTheme.colors.primaryVariant),
            RoundedCornerShape(13.dp)
        )
    }
}
Eskimoaleut answered 26/8, 2021 at 6:46 Comment(0)
P
23

apply always returns this to output. You can change this inside, but in case with modifiers they are immutable, you expected to create a new modifier based on the current one. That's why your border is being ignored.

Instead you can use run, and you have to return something: newly created modifier or this. Check out more about kotlin scope functions.

val selected by remember { mutableStateOf(true) }

val selectableModifier = Modifier
    .padding(horizontal = 5.dp, vertical = 8.dp)
    .run {
        if (selected) {
            border(
                BorderStroke(1.dp, MaterialTheme.colors.primaryVariant),
                RoundedCornerShape(13.dp)
            )
        } else {
            this
        }
    }
Pyramid answered 26/8, 2021 at 7:5 Comment(0)
F
3

When you call a Modifier's method it returns the Modifier itself with new changes. So you have to do something like that

var modifier = Modifier
modifier = modifier.doSomeThing()
modifier = modifier.doOtherThing()

OR use then

val modifier = Modifier
.then(Modifier.doSomeThing())
.then(Modifier.doOtherThing())

You can make conditional then extension method.

fun Modifier.thenIf(condition: Boolean, other: Modifier): Modifier =
    if (condition) this.then(other) else this

And use it like that

val modifier = Modifier
.then(Modifier.doSomeThing())
.then(Modifier.doOtherThing())
.thenIf(canClick==true,Modifier.doConditionalThing())

Furlani answered 13/3, 2023 at 10:25 Comment(0)
S
0

You can use extension like:

/**
 * Calling standard `apply()` on Modifier has no effect,
 * because it returns the origin Modifier, not the updated one.
 *
 * This function will call `run` under the hood instead.
 * It will return updated instance if the [condition] is met or origin Modifier if not.
 */
inline fun Modifier.applyOnModifier(condition: Boolean, block: Modifier.() -> Modifier): Modifier =
    if (condition) block.invoke(this) else this

and call it like:

@Composable
fun MyCustomCardWithClick(
    modifier: Modifier,
    onClick: (() -> Unit)? = null,
) {
    Card(
        modifier = modifier
            .applyOnModifier(onClick != null) {
                clickable { onClick?.invoke() }
            }
    ) {  }
}

Smolensk answered 6/9 at 7:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.