Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting long press events on Chips in Jetpack Compose

I have a list of chips in Jetpack Compose, and I was wondering how it would be possible to detect long press events on them?

Code:

SuggestionChip(
    onClick = {
        onQuickPresetTapped()
    },
    label = {
        Text(text = "${quickPreset.width}x${quickPreset.height}")
    }
)

Currently I have only successfully detected simple click events, although I want the app to be able to detect long click event as well.

I have tried many Stack Overflow solutions, such as the following:

SuggestionChip(
    label = {
        Text(text = "${quickPreset.width}x${quickPreset.height}")
    },
    onClick = { },
    modifier = Modifier.combinedClickable(
        onClick = { onQuickPresetTapped() },
        onLongClick = { onQuickPresetLongPressed() }
    )
)

... which did not fix the problem.

Another thing I tried is wrapping the chip in a box with a long click and click event like so:

Box(
    modifier = Modifier.combinedClickable(
        onClick = { onQuickPresetTapped() },
        onLongClick = { onQuickPresetLongPressed() }
    )
) {
    SuggestionChip(
        onClick = {
            onQuickPresetTapped()
        },
        label = {
            Text(text = "${quickPreset.width}x${quickPreset.height}")
        }
    )
}

... this also did not solve the problem.

How can I get long press events to work on chips? I have tried many things without success.

like image 393
tomtomkt Avatar asked Sep 08 '25 16:09

tomtomkt


1 Answers

I just came up with a solution I like quite a bit. Here's the code and I'll try to explain anything interesting afterward:

  LazyRow() {
    items(chipTitles.size) { i ->
      val inputChipInteractionSource = remember { MutableInteractionSource() }
      Box {
        InputChip(
          label = { Text(text = titles[i]) },
          onClick = {},
          interactionSource = inputChipInteractionSource,
        )
        Box(modifier = Modifier
            .matchParentSize()
            .combinedClickable (
              onLongClick = { onLongPress(i) },
              onClick = { onClick(i) },
              interactionSource = inputChipInteractionSource,
              indication = null,
            ))
      }
    }

The element that makes this work at all is Box. We use a Box firstly as a container around an InputChip. We then use a second Box as something similar to scrim that lies on top of an InputChip. The InputChip is no longer clickable because it is underneath the scrim-like Box. We then use the combinedClickable() Modifier on the scrim-like Box, which allows us to easily handle clicks and long presses. This clickable Box can be a bit bigger than the InputChip, which makes the interaction indication animations a little awkward.

That's where MutableInteractionSource comes into play. MutableInteractionSource is essentially a stream that emits when an interaction has occurred. We attach this InteractionSource to the clickable, scrim-like Box but with indications on this box turned off (setting it to null). This scrim-like Box emits interactions from our provided InteractionSource but does not display interaction inidcation animations. At the same time, we attach this same InteractionSource to the InputChip. So although the InputChip is not actually clickable (it is underneath the scrim-like Box), it still receives a stream of interactions through the InteractionSource and performs indication animations when expected.

Note: combinedClickable is still tagged as @ExperimentalFoundationApi and may be changed or removed in the future.

like image 114
Lucodivo Avatar answered Sep 10 '25 06:09

Lucodivo