为何CoordinatorLayout内collectIsPressedAsState()无法检测短按?
问题:Jetpack Compose自定义文本按钮短按时无法触发按压状态变色
在嵌套于CoordinatorLayout的ComposeView中实现了自定义文本按钮,期望按钮根据按压状态切换文字颜色,但仅长按能触发isPressed变为true,短按时无状态变化,文字颜色也不更新。
复现代码
Activity代码
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val view = this.layoutInflater.inflate(R.layout.activity_main, null) setContentView(view) findViewById<ComposeView>(R.id.compose_view).setContent { CustomTextButton() } } } @Composable fun CustomTextButton() { val interactionSource = remember { MutableInteractionSource() } val isPressed by interactionSource.collectIsPressedAsState() val color = when (isPressed) { true -> Color.Red false -> Color.Black } LaunchedEffect(key1 = isPressed) { println("#### isPressed: $isPressed") } Box( modifier = Modifier .clickable( indication = null, interactionSource = interactionSource, onClick = { println("#### Box clicked") } ) ) { Text( text = "CustomTextButton", color = color ) } }
布局文件
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.compose.ui.platform.ComposeView android:id="@+id/compose_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.coordinatorlayout.widget.CoordinatorLayout>
日志表现
- 长按日志:
2023-02-17 13:31:22.598 ... #### isPressed: true 2023-02-17 13:31:23.047 ... #### Box clicked 2023-02-17 13:31:23.106 ... #### isPressed: false
- 短按日志:
2023-02-17 13:33:12.382 ... #### Box clicked
问题原因
这是因为Compose在CoordinatorLayout这类具备滚动特性的容器内的ComposeView中,对按压状态的触发做了延迟处理,目的是区分点击和滚动操作,但导致短按时无法及时触发isPressed状态变更。
解决方案
方案1:修改布局文件属性
给ComposeView添加android:descendantFocusability="blocksDescendants"属性,让Compose优先处理触摸事件:
<androidx.compose.ui.platform.ComposeView android:id="@+id/compose_view" android:layout_width="match_parent" android:layout_height="match_parent" android:descendantFocusability="blocksDescendants" />
方案2:自定义触摸事件处理
通过pointerInput直接处理按压逻辑,绕过默认的滚动延迟:
@Composable fun CustomTextButton() { val interactionSource = remember { MutableInteractionSource() } val isPressed by interactionSource.collectIsPressedAsState() val color = if (isPressed) Color.Red else Color.Black LaunchedEffect(isPressed) { println("#### isPressed: $isPressed") } val pressModifier = Modifier.pointerInput(interactionSource) { detectTapGestures( onPress = { try { interactionSource.emit(PressInteraction.Press(it)) awaitRelease() } finally { interactionSource.emit(PressInteraction.Release(it)) } }, onTap = { println("#### Box clicked") } ) } Box(modifier = pressModifier) { Text( text = "CustomTextButton", color = color ) } }
内容的提问来源于stack exchange,提问作者LukeTheNuke
相关产品推荐
相关产品推荐

