如何使用Jetpack Compose按钮后面的视图检测单击? [英] How can I detect a click with the view behind a Jetpack Compose Button?
本文介绍了如何使用Jetpack Compose按钮后面的视图检测单击?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
以下代码用于JetBrains桌面合成。它显示了一张上面有一个按钮的卡片,现在如果您单击该卡片,单击的卡片&将被回显到控制台。如果您单击该按钮,它将回显&q;单击的按钮
但是,我正在为卡片寻找一种检测按钮点击的方法。我想在不更改按钮的情况下这样做,这样按钮就不需要知道它在哪张卡上。我希望这样做,以便卡片知道其表面的某些东西被处理,例如显示不同颜色的边框。
所需的结果是,当您单击该按钮时,日志将同时回显";Card单击";和";Button单击";行。我理解为什么不调用mouseClickable
,按钮声明点击已处理。所以我预计我需要使用mouseClickable
以外的另一种鼠标方法。但我无论如何也想不出该用什么。
@OptIn(ExperimentalComposeUiApi::class, androidx.compose.foundation.ExperimentalDesktopApi::class)
@Composable
fun example() {
Card(
modifier = Modifier
.width(150.dp).height(64.dp)
.mouseClickable { println("Clicked card") }
) {
Column {
Button({ println("Clicked button")}) { Text("Click me") }
}
}
}
推荐答案
当BUTTON发现TAP事件时,会将其标记为已消费,从而阻止其他视图接收该事件。这是通过consumeDownChange()
完成的,您可以看到detectTapAndPress
方法,其中Button
here
要覆盖默认行为,您必须重新实现一些手势跟踪。与系统比较的更改列表detectTapAndPress
:
- 我使用
awaitFirstDown(requireUnconsumed = false)
而不是默认的requireUnconsumed = true
,以确保我们使用的是均匀的 - 我使用自己的
waitForUpOrCancellationInitial
而不是waitForUpOrCancellation
:这里我使用awaitPointerEvent(PointerEventPass.Initial)
而不是awaitPointerEvent(PointerEventPass.Main)
,以便即使其他视图会获取事件也能获取它。 - 删除
up.consumeDownChange()
以允许按钮处理触摸。
最终代码:
suspend fun PointerInputScope.detectTapAndPressUnconsumed(
onPress: suspend PressGestureScope.(Offset) -> Unit = NoPressGesture,
onTap: ((Offset) -> Unit)? = null
) {
val pressScope = PressGestureScopeImpl(this)
forEachGesture {
coroutineScope {
pressScope.reset()
awaitPointerEventScope {
val down = awaitFirstDown(requireUnconsumed = false).also { it.consumeDownChange() }
if (onPress !== NoPressGesture) {
launch { pressScope.onPress(down.position) }
}
val up = waitForUpOrCancellationInitial()
if (up == null) {
pressScope.cancel() // tap-up was canceled
} else {
pressScope.release()
onTap?.invoke(up.position)
}
}
}
}
}
suspend fun AwaitPointerEventScope.waitForUpOrCancellationInitial(): PointerInputChange? {
while (true) {
val event = awaitPointerEvent(PointerEventPass.Initial)
if (event.changes.fastAll { it.changedToUp() }) {
// All pointers are up
return event.changes[0]
}
if (event.changes.fastAny { it.consumed.downChange || it.isOutOfBounds(size) }) {
return null // Canceled
}
// Check for cancel by position consumption. We can look on the Final pass of the
// existing pointer event because it comes after the Main pass we checked above.
val consumeCheck = awaitPointerEvent(PointerEventPass.Final)
if (consumeCheck.changes.fastAny { it.positionChangeConsumed() }) {
return null
}
}
}
附注:您需要将implementation("androidx.compose.ui:ui-util:$compose_version")
for Android Compose或implementation(compose("org.jetbrains.compose.ui:ui-util"))
for Desktop Compose添加到build.gradle.kts
中才能使用fastAll
/fastAny
。
用法:
Card(
modifier = Modifier
.width(150.dp).height(64.dp)
.clickable { }
.pointerInput(Unit) {
detectTapAndPressUnconsumed(onTap = {
println("tap")
})
}
) {
Column {
Button({ println("Clicked button") }) { Text("Click me") }
}
}
这篇关于如何使用Jetpack Compose按钮后面的视图检测单击?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文