-
-
Save stevdza-san/ff9dbec0e072d8090e1e6d16e6b73c91 to your computer and use it in GitHub Desktop.
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) | |
} | |
} | |
) | |
} |
Why the onClick callback is never called using the top composable exemple:
@composable
fun HyperlinkText(
modifier: Modifier = Modifier,
fullText: String,
linkText: List,
linkTextColor: Color = Color.Blue,
linkTextFontWeight: FontWeight = FontWeight.Medium,
linkTextDecoration: TextDecoration = TextDecoration.Underline,
hyperlinks: List = listOf(),
fontSize: TextUnit = 24.sp
)
Cant find annotation key or value
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 :)
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 👍
If you have to use @StringRes:
Usage:
if you need a few links: