Создать экранирующий контейнер AnimatedVisibility

Я использую Jetpack Compose (версия 1.1.1) и пытаюсь показать предупреждение в стиле закусочной, исходящее из верхней части экрана, с помощью AnimatedVisibility. Однако, когда я это делаю, оповещение покидает свой контейнер и перекрывает содержимое над ним (в данном случае панель действий). Кроме того, содержимое под ним (кнопка) ожидает завершения анимации, прежде чем изменить свое положение. Это приводит к скачкообразному эффекту. Я хотел бы, чтобы он скользил вниз синхронно с предупреждением.

      @Composable
fun HomeScreen() {
    val showAlert = remember { mutableStateOf(false) }
    val scope = rememberCoroutineScope()
    Column(Modifier.fillMaxHeight()) {
        ActionBar("Home Screen")
        Column {
            Alert(visible = showAlert.value)
            Button(modifier = Modifier.padding(16.dp), onClick = {
                scope.launch {
                    showAlert.value = true
                    delay(1000)
                    showAlert.value = false
                }
            }) {
                Text("Show Alert")
            }
        }

    }

}

@Composable
private fun ActionBar(title: String) {
    TopAppBar(backgroundColor = Color.Blue, contentColor = Color.White) {
        Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 8.dp, end = 8.dp)) {
            Text(title)
        }
    }
}

@Composable
fun Alert(visible: Boolean) {
    AnimatedVisibility(visible = visible, enter = slideInVertically(), exit = slideOutVertically()) {
        Column(Modifier.fillMaxWidth().background(Color.Red)) {
            Text("An error has occurred", Modifier.padding(16.dp), style = TextStyle(Color.White))
        }
    }

}

@Preview
@Composable
fun HomeScreenPreview() {
    Box(Modifier.fillMaxSize().background(Color.White)) {
        HomeScreen()
    }
}

1 ответ

Для проблемы перекрытия вы можете использовать модификатор: Modifier.clipToBounds()

Для «прыгающего эффекта» вы можете поместить текст предупреждения и содержимое страницы в один столбец и анимировать смещение.

      enum class AlertState {
    Collapsed,
    Expanded
}

@Preview
@Composable
fun HomeScreen() {
    val scope = rememberCoroutineScope()
    val alertHeight = 40.dp
    var currentState by remember { mutableStateOf(AlertState.Collapsed) }
    val transition = updateTransition(currentState, label = "")
    val alertOffset by transition.animateDp(label = "") {
        when (it) {
            AlertState.Collapsed -> -alertHeight
            AlertState.Expanded -> 0.dp
        }
    }
    Column(Modifier.fillMaxHeight()) {
        TopAppBar(backgroundColor = Color.Blue, contentColor = Color.White) {
            Row(
                verticalAlignment = Alignment.CenterVertically,
                modifier = Modifier.padding(start = 8.dp, end = 8.dp)
            ) {
                Text("Home Screen")
            }
        }
        Column(
            modifier = Modifier.clipToBounds().offset(y = alertOffset)
        ) {
            Row(
                Modifier.height(alertHeight).fillMaxWidth().background(Color.Red).padding(start = 16.dp)
            ) {
                Text(
                    "An error has occurred", style = TextStyle(Color.White),
                    modifier = Modifier.align(Alignment.CenterVertically)
                )
            }
            Button(modifier = Modifier.padding(16.dp), onClick = {
                scope.launch {
                    currentState = AlertState.Expanded
                    delay(1000)
                    currentState = AlertState.Collapsed
                }
            }) {
                Text("Show Alert")
            }
        }
    }
}

Если ваша высота оповещения не фиксирована, вы можете получить ее с помощью модификатора Modifier.onGloballyPositioned

Другие вопросы по тегам