Compose AnimatedVisibility 转义容器

Compose AnimatedVisibility escapes container

我正在使用 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()
    }
}

对于重叠问题,可以使用修饰符:Modifier.clipToBounds()

对于 'jumpy effect',您可以将警告文本和页面内容放在一个列中并设置偏移动画。

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

获得它