ago*_*st_ 11 android kotlin android-jetpack androidx android-jetpack-compose
我找不到如何链接我Text()使用的 Jetpack Compose。
在撰写之前我要做的就是:
Linkify.addLinks(myTextView, Linkify.EMAIL_ADDRESSES or Linkify.WEB_URLS)
显然,我的 TextView 中包含的所有链接都变成了可点击的链接。
重要提示:文本内容来自 API,链接没有固定位置,内容可能包含多个链接。
我想通过使用 Jetpack Compose 来保持这种行为,但我找不到任何有关这样做的信息。
有人知道吗?
ago*_*st_ 13
如果有人正在寻找解决方案,以下将使任何链接可点击并在文本中设置样式:
@Composable
fun LinkifyText(text: String, modifier: Modifier = Modifier) {
val uriHandler = LocalUriHandler.current
val layoutResult = remember {
mutableStateOf<TextLayoutResult?>(null)
}
val linksList = extractUrls(text)
val annotatedString = buildAnnotatedString {
append(text)
linksList.forEach {
addStyle(
style = SpanStyle(
color = Color.Companion.Blue,
textDecoration = TextDecoration.Underline
),
start = it.start,
end = it.end
)
addStringAnnotation(
tag = "URL",
annotation = it.url,
start = it.start,
end = it.end
)
}
}
Text(
text = annotatedString,
style = MaterialTheme.typography.body1,
onTextLayout = { layoutResult.value = it },
modifier = modifier
.pointerInput(Unit) {
detectTapGestures { offsetPosition ->
layoutResult.value?.let {
val position = it.getOffsetForPosition(offsetPosition)
annotatedString.getStringAnnotations(position, position).firstOrNull()
?.let { result ->
if (result.tag == "URL") {
uriHandler.openUri(result.item)
}
}
}
}
}
)
}
private val urlPattern: Pattern = Pattern.compile(
"(?:^|[\\W])((ht|f)tp(s?):\\/\\/|www\\.)"
+ "(([\\w\\-]+\\.){1,}?([\\w\\-.~]+\\/?)*"
+ "[\\p{Alnum}.,%_=?&#\\-+()\\[\\]\\*$~@!:/{};']*)",
Pattern.CASE_INSENSITIVE or Pattern.MULTILINE or Pattern.DOTALL
)
fun extractUrls(text: String): List<LinkInfos> {
val matcher = urlPattern.matcher(text)
var matchStart: Int
var matchEnd: Int
val links = arrayListOf<LinkInfos>()
while (matcher.find()) {
matchStart = matcher.start(1)
matchEnd = matcher.end()
var url = text.substring(matchStart, matchEnd)
if (!url.startsWith("http://") && !url.startsWith("https://"))
url = "https://$url"
links.add(LinkInfos(url, matchStart, matchEnd))
}
return links
}
data class LinkInfos(
val url: String,
val start: Int,
val end: Int
)
Run Code Online (Sandbox Code Playgroud)
小智 9
您仍然可以使用Linkify.addLinks,但将结果转换为AnnotatedString如下所示:
fun String.linkify(
linkStyle: SpanStyle,
) = buildAnnotatedString {
append(this@linkify)
val spannable = SpannableString(this@linkify)
Linkify.addLinks(spannable, Linkify.WEB_URLS)
val spans = spannable.getSpans(0, spannable.length, URLSpan::class.java)
for (span in spans) {
val start = spannable.getSpanStart(span)
val end = spannable.getSpanEnd(span)
addStyle(
start = start,
end = end,
style = linkStyle,
)
addStringAnnotation(
tag = "URL",
annotation = span.url,
start = start,
end = end
)
}
}
fun AnnotatedString.urlAt(position: Int, onFound: (String) -> Unit) =
getStringAnnotations("URL", position, position).firstOrNull()?.item?.let {
onFound(it)
}
Run Code Online (Sandbox Code Playgroud)
在您的可组合项中使用它,如下所示:
val linkStyle = SpanStyle(
color = MaterialTheme.colors.primary,
textDecoration = TextDecoration.Underline,
)
ClickableText(
text = remember(text) { text.linkify(linkStyle) },
onClick = { position -> text.urlAt(position, onClickLink) },
)
Run Code Online (Sandbox Code Playgroud)
我认为现在更好的解决方案是使用 textview 创建自己的组件,如下所示:
@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()
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7801 次 |
| 最近记录: |