8

Is there any way to use android:autoLink feature on JetPack Compose Text?

I know, that it is maybe not "declarative way" for using this feature in one simple tag/modifier, but maybe there is some easy way for this?

For styling text I can use this way

 val apiString = AnnotatedString.Builder("API provided by")
        apiString.pushStyle(
            style = SpanStyle(
                color = Color.Companion.Blue,
                textDecoration = TextDecoration.Underline
            )
        )
        apiString.append("https://example.com")

        Text(text = apiString.toAnnotatedString())

But, how can I manage clicks here? And would be great, if I programatically say what behaviour I expect from the system (email, phone, web, etc). Like it. works with TextView. Thank you

Bolt UIX
  • 5,988
  • 6
  • 31
  • 58
Sirelon
  • 6,446
  • 5
  • 26
  • 30

2 Answers2

4

We can achieve Linkify kind of TextView in Android Compose like this example below,

@Composable
fun LinkifySample() {
    val uriHandler = UriHandlerAmbient.current

    val layoutResult = remember {
        mutableStateOf<TextLayoutResult?>(null)
    }

    val text = "API provided by"
    val annotatedString = annotatedString {
        pushStyle(
            style = SpanStyle(
                color = Color.Companion.Blue,
                textDecoration = TextDecoration.Underline
            )
        )
        append(text)
        addStringAnnotation(
            tag = "URL",
            annotation = "https://example.com",
            start = 0,
            end = text.length
        )
    }
    Text(
        fontSize = 16.sp,
        text = annotatedString, modifier = Modifier.tapGestureFilter { offsetPosition ->
            layoutResult.value?.let {
                val position = it.getOffsetForPosition(offsetPosition)
                annotatedString.getStringAnnotations(position, position).firstOrNull()
                    ?.let { result ->
                        if (result.tag == "URL") {
                            uriHandler.openUri(result.item)
                        }
                    }
            }
        },
        onTextLayout = { layoutResult.value = it }
    )
}

In the above example, we can see we give the text and also we use addStringAnnotation to set the tag. And using tapGestureFilter, we can get the clicked annotation.

Finally using UriHandlerAmbient.current we can open the link like email, phone, or web.

Reference : https://www.hellsoft.se/rendering-markdown-with-jetpack-compose/

Muthukrishnan Rajendran
  • 11,122
  • 3
  • 31
  • 41
  • 1
    Thanks for your solution, it works fine with URL. But it doesn't work with emails and phone. But for these cases, we can use deepLink such as mailto:example@email.com So, yeah! Thank you! :) – Sirelon Nov 09 '20 at 12:14
  • 1
    More up to date solution here https://stackoverflow.com/a/65656351/2633359 – enyciaa Feb 11 '21 at 12:18
2

The most important part of jetpack compose is the compatibility with native android components.

Create a component that use TextView and use it:

@Composable
fun DefaultLinkifyText(modifier: Modifier = Modifier, text: String?) {
    val context = LocalContext.current
    val customLinkifyTextView = remember {
       TextView(context)
    }
    AndroidView(modifier = modifier, factory = { customLinkifyTextView }) { textView ->
        textView.text = text ?: ""
        LinkifyCompat.addLinks(textView, Linkify.ALL)
        Linkify.addLinks(textView, Patterns.PHONE,"tel:",
            Linkify.sPhoneNumberMatchFilter, Linkify.sPhoneNumberTransformFilter)
        textView.movementMethod = LinkMovementMethod.getInstance()
    }
}

How to use:

 DefaultLinkifyText(
    modifier = Modifier
        .fillMaxWidth()
        .wrapContentHeight(),
    text = "6999999 and https://stackoverflow.com/ works fine"
 )
Jose Pose S
  • 1,175
  • 17
  • 33