1

I have some text with some parts clickable. What I have done is a composable that with a previously built annotated string displays the message that has some url sections:

@Composable private fun MyClickableText( annotatedString: AnnotatedString, modifier: Modifier = Modifier, ) { ClickableText( text = annotatedString, onClick = { annotatedString.getStringAnnotations( tag = "URL", start = it, end = it ).firstOrNull().let { annotatedText -> Timber.d("URL Clicked: ${annotatedText.item}") } }, ) } 

The thing is that composable is used inside another composable that it's clickable as well:

@Composable fun MyItem( ... onClick: () -> Unit = {}, ) { Row( modifier = Modifier .fillMaxWidth() .clickable { onClick() } ) { ... ClickableText(annotatedString) } } 

what happens ther is that the ClickableText always consumes the clicks on it and I would expect to have a way of only consuming them when needed (when its a section that has the URL tag in the example).

What I've tried is to pass an onClick lambda to the MyClickableText composable so that then gets invoked if no url element can be found:

@Composable private fun MyClickableText( annotatedString: AnnotatedString, modifier: Modifier = Modifier, onClick: () -> Unit = {}, ) { ClickableText( text = annotatedString, onClick = { annotatedString.getStringAnnotations( tag = "URL", start = it, end = it ).firstOrNull().let { annotatedText -> Timber.d("URL Clicked: ${annotatedText.item}") } ?: onclick() }, ) } 

and then updating the MyItem to call it as ClickableText(annotatedString, onClick).

While that way we can invoke the Row onClick() in that condition the ripple effect of the Row inside MyItem doesn't work as the click is still consumed inside the ClickableText element.

Is there a way of doing something like returning some value inside the onClick of ClickableText so that it lets the click event continue and not getting consumed by the ClickableText when we want to?

I've been trying to find the answer for some days with no luck.

1 Answer 1

2

I doesn't seem there is a way to make it just work the way you want it unfortunately. But there is a way to bring ripple effect to your solution:
Create a MutableInteractionSource, pass it to your Row's clickable and activate it from ClickableText onClick, something like this:

val interactionSource = remember { MutableInteractionSource() } val scope = rememberCoroutineScope() Row( modifier = Modifier.clickable( interactionSource = interactionSource, indication = LocalIndication.current, onClick = onClick, ) ) { MyClickableText( onClick = { onClick() scope.launch { val pressInteraction = PressInteraction.Press(Offset.Zero) interactionSource.emit(pressInteraction) interactionSource.emit(PressInteraction.Release(pressInteraction)) } } ) } 

One problem is that you don't know the Offset for the press event. For that to work correctly, you will probably have to fork the ClickableText implementation and use the pointerInput that's inside directly.

Sign up to request clarification or add additional context in comments.

1 Comment

Wow, Thank you very much Jan, I've learned new things. I'm still trying to get the correct offset but still it's way better than what I had, upvoted for now and I'll wait a bit cause maybe there is something better but this is really good, thanks.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.