mmm111mmm
mmm111mmm

Reputation: 4115

How can one composible's clicks pass through to a composible underneath?

I have two overlapping boxes. There's a blue box with an offset and low alpha transparency on top of a red box.

Box {
  Box(Modifier
    .size(200.dp)
    .background(Color.Blue)
    .clickable { Log.d("TAG", "I want to receive the clicks from the red box") }
  ) {}
  Box(Modifier
    .size(200.dp)
    .offset(x = 20.dp)
    .alpha(0.2F)
    .background(Color.Red)
    .clickable { Log.d("TAG", "I want my clicks to pass through to the blue box") }
  ) {}
}

How can the red box's clicks pass through to the blue box below?

(Real life scenario: I need this to happen during an animation, just as the box is fading out, and before it's moved elsewhere in the canvas, so the user can click on it just as it's nearly faded out, but click on the now visible composable underneath)

Upvotes: 6

Views: 3859

Answers (1)

Thracian
Thracian

Reputation: 67248

You can do it using MutableInteractionSource and emitting events when Red Composable is touched

@Composable
private fun InteractionSample() {
    val interactionSource = MutableInteractionSource()
    val coroutineScope = rememberCoroutineScope()

    val onClick: () -> Unit = {
        Log.d("TAG", "I want to receive the clicks from the red box")
    }

    Box {
        Box(
            Modifier
                .size(200.dp)
                .background(Color.Blue)
                .clickable(
                    interactionSource = interactionSource,
                    indication = rememberRipple(),
                    onClick = onClick
                )
        ) {}
        Box(
            Modifier
                .size(200.dp)
                .offset(x = 190.dp)
                .alpha(0.2F)
                .background(Color.Red)
                .pointerInput(Unit){
                    detectTapGestures(
                        onPress = {
                            Log.d("TAG", "I want my clicks to pass through to the blue box")
                            coroutineScope.launch {
                                val press = PressInteraction.Press(it)
                                interactionSource.emit(
                                    press
                                )
                                interactionSource.emit(
                                    PressInteraction.Release(press)
                                )
                            }
                            onClick()
                        }
                    )
                }
        ) {}
    }

}

Or implementing it via custom gesture will let ripple on screen till pointer is up or canceled by moving pointer outside Composable with

@Composable
private fun InteractionSample() {
    val interactionSource = MutableInteractionSource()

    val onClick: () -> Unit = {
        Log.d("TAG", "I want to receive the clicks from the red box")
    }

    Box {
        Box(
            Modifier
                .size(200.dp)
                .background(Color.Blue)
                .clickable(
                    interactionSource = interactionSource,
                    indication = rememberRipple(),
                    onClick = onClick
                )
        ) {}
        Box(
            Modifier
                .size(200.dp)
                .offset(x = 190.dp)
                .alpha(0.2F)
                .background(Color.Red)
                .pointerInput(Unit){
                    coroutineScope{
                        forEachGesture {
                            awaitPointerEventScope {
                                  val down =  awaitFirstDown()
                                val press = PressInteraction.Press(down.position)
                                onClick()

                                launch {
                                   interactionSource.emit(
                                       press
                                   )
                               }

                                waitForUpOrCancellation()
                                launch {
                                    interactionSource.emit(
                                        PressInteraction.Release(press)
                                    )
                                }

                            }
                        }
                    }
                }
        ) {}
    }

}

Upvotes: 5

Related Questions