Summary
With Rive() in PassThrough mode as an overlay above sibling composables, any Button / IconButton whose position overlaps Rive's layout bounds doesn't receive onClick, even though the kdoc says PassThrough is the right mode for "an overlay with transparent sections that should allow pointer events through."
Versions
rive-android 11.4.1, androidx.compose.ui 1.10.5
- Samsung Galaxy S25 (SM-S931U1)
Repro
Box(Modifier.fillMaxSize()) {
// Underlay with two buttons at different positions
Column(Modifier.fillMaxSize()) {
Button(
onClick = { Log.d("test", "top fired") },
modifier = Modifier.align(Alignment.Start),
) { Text("Top button") }
Spacer(Modifier.weight(1f))
Button(
onClick = { Log.d("test", "bottom fired") },
) { Text("Bottom button") }
}
// Rive overlay with bounds only covering the bottom half
Rive(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(0.5f)
.align(Alignment.BottomCenter),
pointerInputMode = RivePointerInputMode.PassThrough,
// ...
)
}
- Top button (outside Rive's bounds): fires ✓
- Bottom button (inside Rive's bounds): does NOT fire ✗
Per the PassThrough kdoc and Compose's PointerInputFilter.shareWithSiblings kdoc, the bottom button should fire. It doesn't.
Additional diagnostic: applying graphicsLayer { scaleX = 0.5f; scaleY = 0.5f; clip = true; shape = CircleShape } to Rive's modifier does shrink the failing region, but it follows the scaled rectangular layout bounds — not the CircleShape. Useful for pinpointing the problem but doesn't rescue the overlay use case.
Suggested fix
Add a mode that skips the PointerInputFilter entirely — the Compose equivalent of .allowsHitTesting(false) that rive-ios's own DrillLessonMascotView.swift uses:
enum class RivePointerInputMode { Consume, Observe, PassThrough, None }
// In Rive():
val finalModifier = when (pointerInputMode) {
RivePointerInputMode.None -> modifier
else -> modifier.then(passThroughInputModifier)
}
With None, Rive is a pure drawing layer — Compose hit-testing walks normally and sibling-underneath clickables fire. Matches the iOS pattern.
Summary
With
Rive()inPassThroughmode as an overlay above sibling composables, anyButton/IconButtonwhose position overlaps Rive's layout bounds doesn't receiveonClick, even though the kdoc says PassThrough is the right mode for "an overlay with transparent sections that should allow pointer events through."Versions
rive-android11.4.1,androidx.compose.ui1.10.5Repro
Per the
PassThroughkdoc and Compose'sPointerInputFilter.shareWithSiblingskdoc, the bottom button should fire. It doesn't.Additional diagnostic: applying
graphicsLayer { scaleX = 0.5f; scaleY = 0.5f; clip = true; shape = CircleShape }to Rive's modifier does shrink the failing region, but it follows the scaled rectangular layout bounds — not theCircleShape. Useful for pinpointing the problem but doesn't rescue the overlay use case.Suggested fix
Add a mode that skips the
PointerInputFilterentirely — the Compose equivalent of.allowsHitTesting(false)thatrive-ios's ownDrillLessonMascotView.swiftuses:With
None, Rive is a pure drawing layer — Compose hit-testing walks normally and sibling-underneath clickables fire. Matches the iOS pattern.