Stop Jetpack Compose pointerInteropFilter from consuming input event
Asked Answered
G

1

9

I have a vertical Column that has two children:

  1. A Pager composable (from the Accompanist), which displays Text.
  2. A Canvas composable that draws two arcs, and a circle.

They are ordered in the same order described here. I want the Text to always render behind the Canvas.


Implementation Details

The Canvas composable has a Modifier.pointerInteropFilter that handles MotionEvent.ACTION_DOWN and MotionEvent.ACTION_MOVE. If the event is not within 10% distance of the arc, then it is ignored, and false returned.

My understanding was returning false would indicate that the event has not been consumed, and therefore would be passed through for the Pager to handle - but this is not the case. Once the Modifier.pointerInteropFilter has been registered, the Pager never receives input events, regardless of returning true or false.


Layout

Below is a reduced version of my current implementation, for brevity. I have a Column that renders the Pager first, then the Canvas.

Column(
    modifier = Modifier.fillMaxSize(),
    verticalArrangement = Arrangement.Center
) {
    // The Pager should always be rendered behind the Canvas. This is to
    // prevent the Text from rending on top when being dragged.
    HorizontalPager(
        state = rememberPagerState(pageCount = 8000, initialPage = 4000)
    ) { page ->
        Text(
            modifier = Modifier.fillMaxWidth(),
            text = "25:00",
            textAlign = TextAlign.Center,
            fontSize = 60.sp
        )
    }
}

var progress by remember { mutableStateOf(0.25f) }

ArcSeekBar(progress, false) { change ->
    progress = change
}

In this example, I have hardcoded the pointerInteropFilter to always return false, under the assumption that it would not consume/block the event, allowing it to pass through to the Pager.

@Composable
fun ArcSeekBar(progress: Float, interaction: Boolean, changed: (Float) -> Unit) {
    val sweepAngle = 270.0f

    var width: Int by remember { mutableStateOf(0) }
    var height: Int by remember { mutableStateOf(0) }

    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .aspectRatio(1.0f)
            .onSizeChanged {
                width = it.width
                height = it.height
            }
            .pointerInteropFilter {
                // Reduced for brevity, but whatever the function returns
                // the Pager composable behind it will never receive input events.
                false
            },
    ) {
        // Omitted for brevity, draw two arcs and a circle
    }
}

For reference, my layout produces the following:

enter image description here

Giggle answered 7/5, 2021 at 19:59 Comment(3)
Post the relevant part of your codeCapitulation
@Giggle Did you find any solution for this?Misestimate
@Misestimate Not yet. I have worked around it for now by reducing the width of the HorizontalPager so that it does not overlap the progress bar area. Looks visually poor when dragging the pager text as it clips.Giggle
C
1

With Jetpack Compose 1.4.1 and HorizontalPager from androidx.compose.foundation.pager.HorizontalPager instead of accompanist one this is no longer an issue.

Cephalad answered 15/4, 2023 at 16:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.