How can i add hyperlink to some section of the text of Text component?
With buildAnnotatedString
i can set link section blue and underlined as in image below, but how can i also turn that section into link?
val annotatedLinkString = buildAnnotatedString {
val str = "Click this link to go to web site"
val startIndex = str.indexOf("link")
val endIndex = startIndex + 4
append(str)
addStyle(
style = SpanStyle(
color = Color(0xff64B5F6),
textDecoration = TextDecoration.Underline
), start = startIndex, end = endIndex
)
}
Text(
modifier = modifier
.padding(16.dp)
.fillMaxWidth(),
text = annotatedLinkString
)
I can also get Spanned
but is there any way to use it with Text
?
val str: Spanned = HtmlCompat.fromHtml(
"<a href=\"http://www.github.com\">Github</a>", HtmlCompat.FROM_HTML_MODE_LEGACY
)
To read value entered in TextField in Android Compose, declare a variable, and assign this variable the value in the TextField whenever there is a change in the value. The same process holds for reading value entered in OutlineTextField composable.
Similarly, in Jetpack Compose, a Text element is used to display text on the activity screen. By default, Text cannot create a hyperlink around the text, So, we create a hyperlink using Annonated String and display it using Clickable Text.
Displaying Texts is one of the most basic requirements in any kind of UI framework, be it in mobile, desktop or web. And Jetpack Compose makes this easy and intuitive for us via the Text widget.
By default, Text cannot create a hyperlink around the text, So, we create a hyperlink using Annonated String and display it using Clickable Text. So in this article, we will show you how you could create a Hyperlink at a particular Text Span in Android using Jetpack Compose.
Create an Android Studio Jetpack compose project. No third party dependencies are needed for this project. Add your custom fonts in the fonts folder. Create one under the res if it doesn't exist: Copy the code or download it in the link below, build and run. 1. 2. This example shows you not only how to display Text but also style it.
For a complete answer you can use ClickableText
which returns the position of text, and UriHandler
to open URI in a browser.
val annotatedLinkString: AnnotatedString = buildAnnotatedString {
val str = "Click this link to go to web site"
val startIndex = str.indexOf("link")
val endIndex = startIndex + 4
append(str)
addStyle(
style = SpanStyle(
color = Color(0xff64B5F6),
fontSize = 18.sp,
textDecoration = TextDecoration.Underline
), start = startIndex, end = endIndex
)
// attach a string annotation that stores a URL to the text "link"
addStringAnnotation(
tag = "URL",
annotation = "https://github.com",
start = startIndex,
end = endIndex
)
}
// UriHandler parse and opens URI inside AnnotatedString Item in Browse
val uriHandler = LocalUriHandler.current
// 🔥 Clickable text returns position of text that is clicked in onClick callback
ClickableText(
modifier = modifier
.padding(16.dp)
.fillMaxWidth(),
text = annotatedLinkString,
onClick = {
annotatedLinkString
.getStringAnnotations("URL", it, it)
.firstOrNull()?.let { stringAnnotation ->
uriHandler.openUri(stringAnnotation.item)
}
}
)
The marked answer confuses novices, I give a complete example
Please don't forget to end pushStringAnnotation
with pop()
val annotatedString = buildAnnotatedString {
append("By joining, you agree to the ")
pushStringAnnotation(tag = "policy", annotation = "https://google.com/policy")
withStyle(style = SpanStyle(color = MaterialTheme.colors.primary)) {
append("privacy policy")
}
pop()
append(" and ")
pushStringAnnotation(tag = "terms", annotation = "https://google.com/terms")
withStyle(style = SpanStyle(color = MaterialTheme.colors.primary)) {
append("terms of use")
}
pop()
}
ClickableText(text = annotatedString, style = MaterialTheme.typography.body1, onClick = { offset ->
annotatedString.getStringAnnotations(tag = "policy", start = offset, end = offset).firstOrNull()?.let {
Log.d("policy URL", it.item)
}
annotatedString.getStringAnnotations(tag = "terms", start = offset, end = offset).firstOrNull()?.let {
Log.d("terms URL", it.item)
}
})
final effect
For anyone looking for a reusable copy-paste solution,
Create a new file LinkText.kt
and copy-paste this code,
data class LinkTextData(
val text: String,
val tag: String? = null,
val annotation: String? = null,
val onClick: ((str: AnnotatedString.Range<String>) -> Unit)? = null,
)
@Composable
fun LinkText(
linkTextData: List<LinkTextData>,
modifier: Modifier = Modifier,
) {
val annotatedString = createAnnotatedString(linkTextData)
ClickableText(
text = annotatedString,
style = MaterialTheme.typography.body1,
onClick = { offset ->
linkTextData.forEach { annotatedStringData ->
if (annotatedStringData.tag != null && annotatedStringData.annotation != null) {
annotatedString.getStringAnnotations(
tag = annotatedStringData.tag,
start = offset,
end = offset,
).firstOrNull()?.let {
annotatedStringData.onClick?.invoke(it)
}
}
}
},
modifier = modifier,
)
}
@Composable
private fun createAnnotatedString(data: List<LinkTextData>): AnnotatedString {
return buildAnnotatedString {
data.forEach { linkTextData ->
if (linkTextData.tag != null && linkTextData.annotation != null) {
pushStringAnnotation(
tag = linkTextData.tag,
annotation = linkTextData.annotation,
)
withStyle(
style = SpanStyle(
color = MaterialTheme.colors.primary,
textDecoration = TextDecoration.Underline,
),
) {
append(linkTextData.text)
}
pop()
} else {
append(linkTextData.text)
}
}
}
}
Usage
LinkText(
linkTextData = listOf(
LinkTextData(
text = "Icons made by ",
),
LinkTextData(
text = "smalllikeart",
tag = "icon_1_author",
annotation = "https://www.flaticon.com/authors/smalllikeart",
onClick = {
Log.d("Link text", "${it.tag} ${it.item}")
},
),
LinkTextData(
text = " from ",
),
LinkTextData(
text = "Flaticon",
tag = "icon_1_source",
annotation = "https://www.flaticon.com/",
onClick = {
Log.d("Link text", "${it.tag} ${it.item}")
},
)
),
modifier = Modifier
.padding(
all = 16.dp,
),
)
Screenshot,
Note
UriHandler
or other alternatives if manual control is not required.LinkText
.You can use https://github.com/firefinchdev/linkify-text
Its a single file, you can directly copy it to your project.
Also, it uses Android's Linkify for link detection, which is same as that of TextView
's autoLink
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With