最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - How to completely consume touch events in Jetpack Compose to prevent child clicks? - Stack Overflow

programmeradmin3浏览0评论

I am trying to intercept and consume all click events at the parent level in Jetpack Compose so that child composables (like a Button) do not receive clicks. However, even after calling consume() in awaitPointerEventScope, the child still receives the click event.

Here is my code:

@Composable
fun ParentConsumesClick() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .pointerInput(Unit) {
                awaitPointerEventScope {
                    while (true) {
                        val event = awaitPointerEvent()
                        Log.d("Click", "Consumed in Parent")
                        event.changes.forEach { it.consume() } // Consume touch event
                    }
                }
            }
            .background(Color.Gray),
        contentAlignment = Alignment.Center
    ) {
        Button(onClick = { Log.d("Click", "Child clicked") }) {
            Text("Click Me")
        }
    }
}

Expected Behavior:

  • Clicking anywhere inside the Box should log "Consumed in Parent".
  • The Button inside should not receive any clicks (i.e., "Child clicked" should not be logged).

Actual Behavior:

  • "Consumed in Parent" is logged (showing that the parent receives the event).
  • But the Button still receives the click event and logs "Child clicked".

I am trying to intercept and consume all click events at the parent level in Jetpack Compose so that child composables (like a Button) do not receive clicks. However, even after calling consume() in awaitPointerEventScope, the child still receives the click event.

Here is my code:

@Composable
fun ParentConsumesClick() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .pointerInput(Unit) {
                awaitPointerEventScope {
                    while (true) {
                        val event = awaitPointerEvent()
                        Log.d("Click", "Consumed in Parent")
                        event.changes.forEach { it.consume() } // Consume touch event
                    }
                }
            }
            .background(Color.Gray),
        contentAlignment = Alignment.Center
    ) {
        Button(onClick = { Log.d("Click", "Child clicked") }) {
            Text("Click Me")
        }
    }
}

Expected Behavior:

  • Clicking anywhere inside the Box should log "Consumed in Parent".
  • The Button inside should not receive any clicks (i.e., "Child clicked" should not be logged).

Actual Behavior:

  • "Consumed in Parent" is logged (showing that the parent receives the event).
  • But the Button still receives the click event and logs "Child clicked".
Share Improve this question asked 7 hours ago Ali AsjadAli Asjad 1,9912 gold badges13 silver badges14 bronze badges 1
  • 1 Can you elaborate a little more what your actual goal is? Depending on your goal, you could try to disable the Button or use a Surface Composable. – BenjyTec Commented 6 hours ago
Add a comment  | 

1 Answer 1

Reset to default 0

You need to consume down event for clickable Modifier or Button to not receive click events.

Also since gestures propagate from child to parent you need to change pass from Main to Initial for parent to receive touch first.

You can check out this answer for more details about how gesture system works in Jetpack Compose.

Create a Modifier such as

private fun Modifier.customTouch(
    pass: PointerEventPass,
    onDown: () -> Unit = {},
    onUp: () -> Unit = {}
) = this.then(
    Modifier.pointerInput(pass) {
        awaitEachGesture {
            val down = awaitFirstDown(pass = pass)
            down.consume()
            onDown()
           val up = waitForUpOrCancellation(pass)
            if (up != null) {
                onUp()
            }
        }
    }
)

And apply this Modifier to parent such as

@Preview
@Composable
fun ParentConsumesClick() {

    val context = LocalContext.current
    Box(
        modifier = Modifier
            .fillMaxSize()
            .customTouch(
                pass = PointerEventPass.Initial,
                onDown = {
                    Toast
                        .makeText(context, "Parent Touched", Toast.LENGTH_SHORT)
                        .show()
                },
                onUp = {
                    Toast
                        .makeText(context, "Parent Up", Toast.LENGTH_SHORT)
                        .show()
                }
            )
            .background(Color.Gray),
        contentAlignment = Alignment.Center
    ) {
        Button(onClick = {
            Toast.makeText(context, "Child clicked", Toast.LENGTH_SHORT).show()
        }) {
            Text("Click Me")
        }
    }
}

Also if you want to apply ripple on this click you can add InteractionSouce and Modifier.indication.

发布评论

评论列表(0)

  1. 暂无评论