Home > Software engineering >  How to change passed-in modifier before using it?
How to change passed-in modifier before using it?

Time:10-23

I'm trying to add some conditional logic to the modifier parameter in my custom composable before using it. How can this be done? For example

@Composable
fun MyComposable(index: Int, myModifier: Modifier = Modifier) {

    if (index == 0) {
        myModifier.background(Color.Red)
    } else {
        myModifier.background(Color.Blue)
    }

    Column(modifier = myModifier) { 
        ...
    }

Compose simply ignores changes made to myModifier

For now, I'm creating a new variable of type Modifier and using that instead, but I'm wondering if there is a better way using the original passed-in modifier.

CodePudding user response:

Compose simply ignores changes made to myModifier

It doesn't ignore but when you chain Modifiers you create new instance of Modifier if any part of it has changed.

And Modifiers also get recomposed when the variable they read changes, in your instance when Modifier.background() changes there is a new Modifier created using part of the Modifier that doesn't change, in the example below size and the new Modifier for background.

You need to assign this new Modifier to your Composables

enter image description here

@Composable
private fun ModifierRecompositionSample() {
    var counter by remember { mutableStateOf(0) }

    Column {

        val myModifier = Modifier.fillMaxWidth()

        Text(text = "MyModifier: $myModifier", modifier = myModifier)


        val newModifier = if (counter == 0) {
            myModifier.background(Color.Red)
        } else {
            myModifier.background(Color.Blue)
        }

        Text(text = "MyModifier: $myModifier", modifier = myModifier)
        Text(
            color = Color.White,
            text = "newModifier: ${newModifier.hashCode()}, newModifier: $newModifier",
            modifier = newModifier
        )

        Button(onClick = { counter   }) {
            Text("Counter: $counter")
        }
    }
}

You can check out this question if you with to investigate composition phases and Modifier recomposition

How I can display data for specific item

CodePudding user response:

Its not being ignored, but it won't work by simply calling

myModifier.background( <color> )

because you aren't setting it to the same Modifier instance or any Modifier instance that your Column will use.

You cannot do this and it won't compile

@Composable
fun MyComposable(index: Int, myModifier : Modifier = Modifier) {

    myModifier = if (index == 0) {
        Modifier.background(Color.Red)
    } else {
        Modifier.background(Color.Blue)
    }

    Column(modifier = myModifier) { ... }
}

because the Modifier parameter (myModifier) is implicitly val and its final, so you'll see a compile error

Val cannot be reassigned

However you can do something like this,

@Composable
fun MyComposable(index: Int) {

    val myModifier = if (index == 0) {
        Modifier.background(Color.Red)
    } else {
        Modifier.background(Color.Blue)
    }

    Column(modifier = myModifier) { ... }
}

or something like this,

@Composable
fun MyComposable(
    index : Int,
    myModifier: Modifier = Modifier
) {
    Column(
        modifier = myModifier
            .background(
                if (index == 0) Color.Red else Color.Blue
            )
    ) { ... }
}

or when passing it to the MyComposable. I'm assuming that index is just used for a conditional background color though so I removed it as a parameter below

    // ... Somewhere in your composable outside ...

    val index = 5        
 
    MyComposable(
        // removed index arg
        myModifier = Modifier
            .background(
                if (index == 0) Color.Red else Color.Blue
            )    
    )
}


...
...
...


@Composable
fun MyComposable(
    // removed index param
    myModifier: Modifier = Modifier
) {
    Column(modifier = myModifier)
    ) { ... }
}

I personally prefer the third approach, where Modifier properties of a root/parent composable are controlled outside, in your case the Column(root/parent) background of your MyComposable contents.

  • Related