Jetpack Compose:AnimatedVisibility动画时IconButton透明度异常问题
问题描述
在Jetpack Compose的Row布局内放置两个IconButton,第二个默认隐藏,点击第一个按钮触发显示。使用AnimatedVisibility显示第二个按钮时,第一个按钮的背景透明度无法保持正常,效果如下:

当前代码:
Row( horizontalArrangement = Arrangement.Center, modifier = Modifier .fillMaxWidth() .padding(32.dp) ) { var isClicked by remember { mutableStateOf(false) } IconButton( onClick = { isClicked = !isClicked }, modifier = Modifier.size(64.dp) ) { val icon: ImageVector = if (isClicked) { Icons.Filled.NotStarted } else { Icons.Filled.PauseCircle } Icon( imageVector = icon, contentDescription = "", modifier = Modifier.size(64.dp) ) } AnimatedVisibility( visible = isClicked, ) { IconButton( onClick = { }, modifier = Modifier .padding(start = 24.dp) .size(64.dp) ) { Icon( imageVector = Icons.Filled.StopCircle, contentDescription = "", modifier = Modifier.size(64.dp) ) } } }
问题原因
第二个按钮显示时,Row会重新计算布局,导致第一个IconButton的位置发生偏移,触发了IconButton内部的交互状态(类似按压反馈的半透明效果),而重组过程中交互源被重置,最终出现透明度异常。
解决办法
方法一:固定IconButton的交互源
给第一个IconButton手动传入用remember保存的交互源,避免重组时重置交互状态:
Row( horizontalArrangement = Arrangement.Center, modifier = Modifier .fillMaxWidth() .padding(32.dp) ) { var isClicked by remember { mutableStateOf(false) } // 持久化交互源,防止重组时重置状态 val interactionSource = remember { MutableInteractionSource() } IconButton( onClick = { isClicked = !isClicked }, modifier = Modifier.size(64.dp), interactionSource = interactionSource ) { val icon: ImageVector = if (isClicked) { Icons.Filled.NotStarted } else { Icons.Filled.PauseCircle } Icon( imageVector = icon, contentDescription = "切换按钮状态", modifier = Modifier.size(64.dp) ) } AnimatedVisibility( visible = isClicked, enter = fadeIn() + slideInHorizontally(), exit = fadeOut() + slideOutHorizontally() ) { IconButton( onClick = { }, modifier = Modifier .padding(start = 24.dp) .size(64.dp) ) { Icon( imageVector = Icons.Filled.StopCircle, contentDescription = "停止按钮", modifier = Modifier.size(64.dp) ) } } }
方法二:提前占位避免布局移动
给第二个按钮的位置提前设置固定宽度的占位容器,防止第一个按钮因布局重排产生位置偏移:
Row( horizontalArrangement = Arrangement.Center, modifier = Modifier .fillMaxWidth() .padding(32.dp) ) { var isClicked by remember { mutableStateOf(false) } IconButton( onClick = { isClicked = !isClicked }, modifier = Modifier.size(64.dp) ) { val icon: ImageVector = if (isClicked) { Icons.Filled.NotStarted } else { Icons.Filled.PauseCircle } Icon( imageVector = icon, contentDescription = "切换按钮状态", modifier = Modifier.size(64.dp) ) } // 提前占位,宽度为第二个按钮+内边距的总宽度 Box(modifier = Modifier.width(24.dp + 64.dp)) { AnimatedVisibility( visible = isClicked, enter = fadeIn() + slideInHorizontally(), exit = fadeOut() + slideOutHorizontally() ) { IconButton( onClick = { }, modifier = Modifier.size(64.dp) ) { Icon( imageVector = Icons.Filled.StopCircle, contentDescription = "停止按钮", modifier = Modifier.size(64.dp) ) } } } }
内容的提问来源于stack exchange,提问作者John V.
相关产品推荐
相关产品推荐

