When using Jetpack Compose to build UI, Modifier and State are two inseparable concepts. Modifier is responsible for customizing the external behavior of the UI, while State manages the dynamic changes of the UI. The two usually need to collaborate to reflect rich interactive effects. This article will discuss this topic, explain the role of State in Modifier, and give specific example code.

The role of State in Modifier

Many times, we hope that Modiifer can not only statically modify the UI, but also dynamically change the style or behavior of the UI according to changes in state. This requires the introduction of the concept of State in Modifier.

For example, we could create one ToggleableModifierthat Booleandecides whether to apply an effect based on a state:

@Composable
fun ToggleableModifier(
    isEnable: Boolean,
    enableModifier: Modifier,
    disableModifier: Modifier,
    content: @Composable () -> Unit
) {
    Box(
        modifier = if (isEnabled) enableModifier else disableModifier
    ) {
        content()
    }
}

In this example, ToggleableModifierisEnablestate is received as input. Depending on the value of this state, it will apply one of enabledModifieror . disabledModifierIn this way, we can dynamically switch the effect of Modifier.

Use ToggleableModifieris very simple, just provide the corresponding state and Modifier instance:

val isEnabled = remember { mutableStateOf(true) }

ToggleableModifier(
    isEnabled = isEnabled.value,
    enableModifier = Modifier
        .background(Color.Green)
        .padding(16.dp)
    disabledModifier = Modifier
        .background(Color.Gray)
        .padding(8.dp)
) {
    Text("Hello Modifier")
}

This code will isEnableddisplay a text with different background colors and padding depending on the value of the state. When isEnabledtrue, the background color is green and the padding is 16dp; when isEnabledfalse, the background color is gray and the padding is 8dp.

State-driven animation effects

In addition to static style switching, we can also use State to achieve animation effects. Jetpack Compose provides animateXXXa series of functions that allow us to calculate an animatable value based on the state value.

For example, the following code implements a zoom animation:

@Composable
fun ScaleAnimation(scale: Float) {
    val animatedScale = animateFloatAsState(
        targetValue = scale,
        animationSpec = tween(durationMillis = 1000)
    )
    
    Box(
        modifier = Modifier
            .graphicsLayer(
                scaleX = animatedScale.value,
                scaleY = animatedScale.value
            )
    ) {
        Text("Hello Modifier")
    }
}

In this code, we use animateFloatAsStatea function to get an animatable Floatvalue that transitions from the current value to the target value in 1000 milliseconds scale. We then apply this animated value to graphicsLayerthe scaleXand scaleYproperties to achieve the zoom animation effect.

Whenever scalethe value changes, the animation automatically restarts. Therefore, we can scaletreat it as a state and trigger animations based on changes in the state:

val scale = remember { mutableStateOf(1f) }

ScaleAnimation(scale = scale.value)

// 
Button(onClick = { scale.value = if (scale.value == 1f) 2f else 1f }) {
    Text("Toggle Scale")
}

This code defines a scalestate with an initial value of 1f. When we click the button, scalethe value of will switch between 1f and 2f, triggering the zoom animation to play.

Through the above examples, we can see that the cooperation of Stateand Modifiercan achieve a variety of rich UI effects, including style switching, animation, etc. State is responsible for managing dynamic changes in the UI, while Modifier adjusts the appearance and behavior of the UI based on the value of State.