https://kotlinlang.org logo
#compose
Title
# compose
j

Jan Skrasek

06/09/2023, 1:28 PM
I have two slots
@Composable () -> Unit
, both can render a Text. Both slots can have an if in it, so they may not render anything. I need to animate between those two slots conditionally, i.e. show the second one if the first does not render anything. If they would be nullable, there is a way is to utilize AnimatedContent, e.g.
Copy code
error: @Composable (() -> Unit)? = null,
    info: @Composable (() -> Unit)? = null,
) {
    val state = when {
        error != null -> Message.Error(error)
        info != null -> <http://Message.Info|Message.Info>(info)
        else -> null
    }
    AnimatedContent(state) { state -> ... }
But I'd like to drop the nullability and allow making the if inside the slot. After hours I don't see a way. Couldn't LookaheadScope help here?
A hacky way with SubcomposeLayout would be
Copy code
error: @Composable () -> Unit,
    info: @Composable () -> Unit,
) {
    SubcomposeLayout { constraints ->
        val errorPlaceable = subcompose("error") {
            error()
        }.firstOrNull()?.measure(constraints)
        val infoPlaceable = subcompose("info") {
            info()
        }.firstOrNull()?.measure(constraints)

        val hasError = errorPlaceable != null && errorPlaceable.height > 0
        val hasInfo = infoPlaceable != null && infoPlaceable.height > 0
        val state = when {
            hasError -> Message.Error(error)
            hasInfo -> <http://Message.Info|Message.Info>(info)
            else -> null
        }

        val messagePlaceable = subcompose("message") {
            AnimatedContent(state) { state -> }
        }.first().measure(constraints)

        layout(messagePlaceable.width, messagePlaceable.height) {
            messagePlaceable.placeRelative(0, 0)
        }
    }
but sadly then I cannot use this component in combination with intrinsic measuring 😞
2 Views