【问题标题】:Linkify with Compose Text使用撰写文本链接
【发布时间】:2021-02-10 03:27:36
【问题描述】:

我找不到如何使用 Jetpack Compose 链接我的 Text()

在作曲之前,我要做的就是:

Linkify.addLinks(myTextView, Linkify.EMAIL_ADDRESSES or Linkify.WEB_URLS)

显然,我的 TextView 中包含的所有链接都变成了可点击的链接。

重要提示:Text 的内容来自 API,链接没有固定的位置,内容可能包含多个链接。

我想通过使用 Jetpack Compose 来保持这种行为,但我找不到任何关于这样做的信息。

有人知道吗?

【问题讨论】:

标签: android kotlin androidx android-jetpack android-jetpack-compose


【解决方案1】:

如果有人正在寻找解决方案,以下内容将使您的文本中的任何链接都可点击并设置样式:

@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
)

【讨论】:

    【解决方案2】:

    您可以使用AnnotatedString 来实现此行为。

    文档:https://developer.android.com/reference/kotlin/androidx/compose/ui/text/AnnotatedString

    另外,这个可以帮助你:

    AutoLink for Android Compose Text

    【讨论】:

      【解决方案3】:

      我认为目前更好的解决方案是使用这样的 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()
          }
      }
      

      【讨论】:

        【解决方案4】:

        根据以上答案, 你可以使用https://github.com/firefinchdev/linkify-text

        它是一个文件,你可以直接将它复制到你的项目中。

        另外,它使用Android的Linkify进行链接检测,与TextViewautoLink相同。

        【讨论】:

          【解决方案5】:

          我采用了一个类似但更简单的解决方案来获得正确的 Material Design 外观:

          @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)
                }
              },
            )
          }
          

          【讨论】:

            【解决方案6】:

            这是一个示例,如果您在一个句子中有多个可点击的单词并且您想在应用程序中导航:

                @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)
                            }
                        }
                    )
               }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-09-29
              • 2021-02-20
              • 1970-01-01
              • 2020-11-03
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多