oleksandrbalan / modalsheet

Modal Sheet library for Jetpack Compose
Apache License 2.0
121 stars 6 forks source link

[ModalSheet] No exit animation when ModalSheet has dynamic content #1

Closed oleksandrbalan closed 2 years ago

oleksandrbalan commented 2 years ago

Description

Sometimes it is needed to show dynamic data in modal sheet content. Imagine error bottom sheet use-case, where if Error is not null we need to show modal, otherwise hide it. We could either wrap ModalSheet in "if" condition to show only for non-null error, or adjust content (which is animated) for null error.

Both possible solutions did not provide good experience. Either there is no exit animation, or content is "blinking" when animating out.

Sample


data class ErrorData(val title: String, val message: String)

val error = rememberSaveable { mutableStateOf<ErrorData?>(null) }

Box(
    contentAlignment = Alignment.Center,
    modifier = Modifier
        .fillMaxSize()
        .padding(padding)
) {
    Button(onClick = {
        error.value = ErrorData(
            title = "Error",
            message = "Oops, an error occurred"
        )
    }) {
        Text(text = "Error!")
    }
}

// Solution #1 - wrap in if condition
val errorValue = error.value
if (errorValue != null) {
    ModalSheet(
        visible = true,
        onDismiss = { error.value = null }
    ) {
        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(SpacingSmall),
            modifier = Modifier
                .fillMaxWidth()
                .navigationBarsPadding()
                .padding(SpacingMedium)
        ) {
            Text(
                text = errorValue.title,
                style = MaterialTheme.typography.h4
            )
            Text(
                text = errorValue.message,
            )
        }
    }
}

// Solution #2 - null content is visible when animated out
ModalSheet(
    visible = error.value != null,
    onDismiss = { error.value = null }
) {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(SpacingSmall),
        modifier = Modifier
            .fillMaxWidth()
            .navigationBarsPadding()
            .padding(SpacingMedium)
    ) {
        Text(
            text = error.value?.title.orEmpty(),
            style = MaterialTheme.typography.h4
        )
        Text(
            text = error.value?.message.orEmpty(),
        )
    }
}

Video

First solution to wrap in if condition, results in no exit animation. https://user-images.githubusercontent.com/20944869/167183075-409de54f-6954-4206-bc90-b488755e6958.mp4

Second solution to use null in content, results in "empty" content during exit animation. https://user-images.githubusercontent.com/20944869/167187758-c1d16bb1-d21e-44ec-adf1-78bf76763c3a.mp4