Last active
September 6, 2024 09:40
-
-
Save stevdza-san/ff9dbec0e072d8090e1e6d16e6b73c91 to your computer and use it in GitHub Desktop.
Embedd a Hyperlink within a Text using Jetpack Compose.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.compose.foundation.text.ClickableText | |
import androidx.compose.runtime.Composable | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.platform.LocalUriHandler | |
import androidx.compose.ui.text.SpanStyle | |
import androidx.compose.ui.text.buildAnnotatedString | |
import androidx.compose.ui.text.font.FontWeight | |
import androidx.compose.ui.text.style.TextDecoration | |
import androidx.compose.ui.unit.TextUnit | |
@Composable | |
fun HyperlinkText( | |
modifier: Modifier = Modifier, | |
fullText: String, | |
linkText: List<String>, | |
linkTextColor: Color = Color.Blue, | |
linkTextFontWeight: FontWeight = FontWeight.Medium, | |
linkTextDecoration: TextDecoration = TextDecoration.Underline, | |
hyperlinks: List<String> = listOf("https://stevdza-san.com"), | |
fontSize: TextUnit = TextUnit.Unspecified | |
) { | |
val annotatedString = buildAnnotatedString { | |
append(fullText) | |
linkText.forEachIndexed { index, link -> | |
val startIndex = fullText.indexOf(link) | |
val endIndex = startIndex + link.length | |
addStyle( | |
style = SpanStyle( | |
color = linkTextColor, | |
fontSize = fontSize, | |
fontWeight = linkTextFontWeight, | |
textDecoration = linkTextDecoration | |
), | |
start = startIndex, | |
end = endIndex | |
) | |
addStringAnnotation( | |
tag = "URL", | |
annotation = hyperlinks[index], | |
start = startIndex, | |
end = endIndex | |
) | |
} | |
addStyle( | |
style = SpanStyle( | |
fontSize = fontSize | |
), | |
start = 0, | |
end = fullText.length | |
) | |
} | |
val uriHandler = LocalUriHandler.current | |
ClickableText( | |
modifier = modifier, | |
text = annotatedString, | |
onClick = { | |
annotatedString | |
.getStringAnnotations("URL", it, it) | |
.firstOrNull()?.let { stringAnnotation -> | |
uriHandler.openUri(stringAnnotation.item) | |
} | |
} | |
) | |
} |
Now that ClickableText
in Jetpack Compose is deprecated, this is my implementation, of course inspired by @stevdza-san's solution.
import androidx.compose.foundation.text.LinkAnnotation
import androidx.compose.foundation.text.TextLinkStyles
import androidx.compose.foundation.text.withLink
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.TextUnit
@Composable
fun HyperlinkText(
modifier: Modifier = Modifier,
text: String,
linkText: List<String>,
hyperlinks: List<String>,
linkTextColor: Color = MaterialTheme.colorScheme.primary,
linkTextFontWeight: FontWeight = FontWeight.Normal,
linkTextDecoration: TextDecoration = TextDecoration.Underline,
fontSize: TextUnit = TextUnit.Unspecified,
fontFamily: FontFamily = FontFamily.Monospace
) {
val uriHandler = LocalUriHandler.current
val annotatedString = buildAnnotatedString {
var lastIndex = 0
linkText.forEachIndexed { index, link ->
val startIndex = text.indexOf(link, lastIndex)
val endIndex = startIndex + link.length
if (startIndex > lastIndex) append(text.substring(lastIndex, startIndex))
val linkUrL = LinkAnnotation.Url(
hyperlinks[index], TextLinkStyles(
SpanStyle(
color = linkTextColor,
fontSize = fontSize,
fontWeight = linkTextFontWeight,
textDecoration = linkTextDecoration,
fontFamily = fontFamily
)
)
) {
val url = (it as LinkAnnotation.Url).url
uriHandler.openUri(url)
}
withLink(linkUrL) { append(link) }
append(" ")
lastIndex = endIndex + 1
}
if (lastIndex < text.length) {
append(text.substring(lastIndex))
}
addStyle(
style = SpanStyle(
fontSize = fontSize, fontFamily = fontFamily
), start = 0, end = text.length
)
}
Text(text = annotatedString, modifier = modifier)
}
Thanks 👍
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This implementation as many others online does not work well with Accesibility. TalkBack is not reading each link individually and by that they are not triggered. I'm working on this and if I have a solution for it in Compose only i'll share it here. In the meantime you can maybe can be aware of it too :)