Compose自定义clickableWithScaleAnimation添加粘性顶栏后失效问题
InteractionSource 生命周期与重组上下文脱离
粘性顶栏中直接保存Composable实例到状态的做法,会导致自定义Modifier里的interactionSource无法绑定到当前Composable的重组上下文。当指定indication = null时,Compose完全依赖传入的interactionSource追踪交互状态(如按压、点击),如果这个interactionSource的生命周期和UI重组周期不匹配,就会出现动画不触发、点击无响应的情况。而默认clickable会自动创建内部绑定的interactionSource,不受状态保存Composable的影响。Composable 实例固化导致的上下文丢失
若粘性顶栏通过remember保存了整个Composable的lambda(如val bar = remember { { CustomBar() } }),该Composable的上下文会被固化,后续重组时无法关联新的交互事件流,直接导致依赖交互状态的自定义Modifier失效。
放弃保存Composable实例到状态
粘性顶栏的正确实现应该通过状态控制显示逻辑,而非保存UI实例。比如用mutableStateOf<Boolean>标记是否进入粘性状态,在布局中根据状态条件渲染顶栏:val isSticky = remember { mutableStateOf(false) } Box(modifier = Modifier.fillMaxSize()) { // 滚动内容区域 LazyColumn( modifier = Modifier.fillMaxSize(), state = rememberLazyListState() ) { // 内容项 } // 根据状态渲染粘性顶栏 if (isSticky.value) { StickyTopBar(modifier = Modifier.align(Alignment.TopCenter)) } }确保InteractionSource与当前Composable绑定
在使用自定义clickableWithScaleAnimation时,必须在目标Composable内部通过remember创建interactionSource,而非复用外部或状态中的实例:@Composable fun ClickableItem() { val interactionSource = remember { MutableInteractionSource() } val isPressed by interactionSource.collectIsPressedAsState() Box( modifier = Modifier .clickableWithScaleAnimation(interactionSource) { // 点击逻辑 } .scale(if (isPressed) 0.95f else 1f, animationSpec = tween(150)) ) { // 内容 } }同时检查自定义Modifier的实现,确保
interactionSource被正确传递给底层clickable,并且动画逻辑基于interactionSource的状态流。升级Compose版本验证
Compose 1.3.0存在部分交互系统的已知问题,升级到1.4.x及以上稳定版本,可能直接修复由于版本bug导致的交互失效问题。
内容的提问来源于stack exchange,提问作者Morten Holmgaard

