Создать экранирующий контейнер 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