我找不到如何使用Jetpack合成链接我的Text()。在作曲之前,我要做的就是:Linkify.addLinks(myTextView, Linkify.EMAIL_ADDRESSES or Linkify.WEB_URLS)显然,我的TextView中包含的所有链接都变成了可点击的链接。重要提示:文本的内容来自API,链接没有固定的位置,内容可能包含多个链接。我想在使用Jetpack Compose时保持此行为,但我找不到有关此操作的任何信息。有人知道吗?
Text()
Linkify.addLinks(myTextView, Linkify.EMAIL_ADDRESSES or Linkify.WEB_URLS)
rdlzhqv91#
如果有人正在寻找一个解决方案,以下将使任何链接可点击和样式在您的文本:
@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, 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) } } } } }, onTextLayout = { layoutResult.value = it } ) } 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 )
2guxujil2#
我认为现在更好的解决方案是使用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() } }
ymdaylpp3#
您仍然可以使用Linkify.addLinks,但将结果转换为AnnotatedString,如下所示:
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) }
在你的组合中使用它,就像这样:
val linkStyle = SpanStyle( color = MaterialTheme.colors.primary, textDecoration = TextDecoration.Underline, ) ClickableText( text = remember(text) { text.linkify(linkStyle) }, onClick = { position -> text.urlAt(position, onClickLink) }, )
7ajki6be4#
您可以使用AnnotatedString来实现此行为。文件:https://developer.android.com/reference/kotlin/androidx/compose/ui/text/AnnotatedString此外,这一条可能会帮助您:AutoLink for Android Compose Text
sf6xfgos5#
根据以上答案,您可以使用https://github.com/firefinchdev/linkify-text它是一个单独的文件,您可以直接将其复制到您的项目中。此外,它使用Android的Linkify进行链接检测,这与TextView的autoLink相同。
TextView
autoLink
brqmpdu16#
一个类似但更简单的解决方案,我用它来获得适当的材质设计外观和感觉:
@Composable fun BodyWithLinks(body: String, modifier: Modifier = Modifier) { AndroidView( modifier = modifier, factory = { context -> (MaterialTextView(context) as AppCompatTextView).apply { val spannableString = SpannableString(body) Linkify.addLinks(spannableString, Linkify.ALL) text = spannableString setTextAppearance(R.style.Theme_Body_1) } }, ) }
9njqaruj7#
如果您在一个句子中有多个可单击的单词,并且您希望在应用程序中导航,则可以使用以下示例:
@Composable fun InformativeSignUpText() { val informativeText = stringResource(R.string.sign_up_already_have_an_account) val logInSubstring = stringResource(R.string.general_log_in) val supportSubstring = stringResource(R.string.general_support) val logInIndex = informativeText.indexOf(logInSubstring) val supportIndex = informativeText.indexOf(supportSubstring) val informativeAnnotatedText = buildAnnotatedString { append(informativeText) addStyle( style = SpanStyle( color = MaterialTheme.colors.primary ), start = logInIndex, end = logInIndex + logInSubstring.length ) addStringAnnotation( tag = logInSubstring, annotation = logInSubstring, start = logInIndex, end = logInIndex + logInSubstring.length ) addStyle( style = SpanStyle( color = MaterialTheme.colors.primary ), start = supportIndex, end = supportIndex + supportSubstring.length ) addStringAnnotation( tag = supportSubstring, annotation = supportSubstring, start = supportIndex, end = supportIndex + supportSubstring.length ) } ClickableText( modifier = Modifier.padding( top = 16.dp ), style = MaterialTheme.typography.subtitle1.copy( color = Nevada ), text = informativeAnnotatedText, onClick = { offset -> informativeAnnotatedText.getStringAnnotations( tag = logInSubstring, start = offset, end = offset ).firstOrNull()?.let { Log.d("mlogs", it.item) } informativeAnnotatedText.getStringAnnotations( tag = supportSubstring, start = offset, end = offset ).firstOrNull()?.let { Log.d("mlogs", it.item) } } ) }
e0uiprwp8#
假设你已经有了一个Spanned,它可能包含了可点击的span(也就是说你已经完成了linkify部分),那么你可以使用如下代码:
Spanned
@Composable fun StyledText(text: CharSequence, modifier: Modifier = Modifier) { val clickable = rememberSaveable { text is Spanned && text.getSpans(0, text.length, ClickableSpan::class.java).isNotEmpty() } AndroidView( modifier = modifier, factory = { context -> TextView(context).apply { if (clickable) { movementMethod = LinkMovementMethod.getInstance() } } }, update = { it.text = text } ) }
这也将渲染可能存在的任何其他跨度类型。
8条答案
按热度按时间rdlzhqv91#
如果有人正在寻找一个解决方案,以下将使任何链接可点击和样式在您的文本:
2guxujil2#
我认为现在更好的解决方案是使用textview创建自己的组件,如下所示:
ymdaylpp3#
您仍然可以使用
Linkify.addLinks
,但将结果转换为AnnotatedString
,如下所示:在你的组合中使用它,就像这样:
7ajki6be4#
您可以使用
AnnotatedString
来实现此行为。文件:https://developer.android.com/reference/kotlin/androidx/compose/ui/text/AnnotatedString
此外,这一条可能会帮助您:
AutoLink for Android Compose Text
sf6xfgos5#
根据以上答案,您可以使用https://github.com/firefinchdev/linkify-text
它是一个单独的文件,您可以直接将其复制到您的项目中。
此外,它使用Android的Linkify进行链接检测,这与
TextView
的autoLink
相同。brqmpdu16#
一个类似但更简单的解决方案,我用它来获得适当的材质设计外观和感觉:
9njqaruj7#
如果您在一个句子中有多个可单击的单词,并且您希望在应用程序中导航,则可以使用以下示例:
e0uiprwp8#
假设你已经有了一个
Spanned
,它可能包含了可点击的span(也就是说你已经完成了linkify部分),那么你可以使用如下代码:这也将渲染可能存在的任何其他跨度类型。