Android Studio 如何在Android Jetpack Compsoe上使字符串中的一个单词可点击?

nzkunb0c  于 2023-03-03  发布在  Android
关注(0)|答案(2)|浏览(163)

直到最近,我一直使用XML来创建我的屏幕,并且我知道如何使用这些XML来使某些TextView可点击。
现在,我正在过渡到专门使用JetpackCompose,不再依赖XML。
我目前正在尝试做的是让文本的一部分有一个关键字,(如果点击)将让你去另一个屏幕上的应用程序。
例如,如果我的文本说“Click here to go to the second screen“,那么当你点击“这里”时,它应该会把你带到另一个屏幕。我在网上看了Compose的资源,上面建议使用ClickableText,但这使得整个句子都可以点击,而只是让“这里”变成不同的颜色,这不是我想要的。
对于撰写,什么是最好的方式,我有一个文本,可以有上面的句子,但只有一个词(“这里”)可点击,并做点击动作?

kq0g1dla

kq0g1dla1#

你可以通过buildAnnotatedString来实现以上的功能。在这里定义你的文本并传入可点击的文本

@Composable
    fun SpannableTextScreen() {
    
        val text = buildAnnotatedString {
            append("Click ")
            pushStringAnnotation(tag = "click", annotation = "click")
            withStyle(
                SpanStyle(
                    textDecoration = TextDecoration.Underline,
                    color = Color.Red
                )
            ) {
                append("here ")
            }
            pop()
            append("to go to the second screen")
        }
        val context = LocalContext.current
    
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(horizontal = 20.dp),
            contentAlignment = Alignment.Center
        ) {
            ClickableText(text = text, onClick = { offset ->
                text.getStringAnnotations(tag = "click", start = offset, end = offset).firstOrNull()
                    ?.let {
                        // on click operation here
                        Toast.makeText(context, "hey", Toast.LENGTH_SHORT).show()
                    }
            })
        }
    
    }

只有here文本是可点击的,现在当你点击here一个吐司将显示,您可以根据您的要求修改

n9vozmp4

n9vozmp42#

正确的答案已经设置好了,我只是试着扩展它,使它更可重用,你可以这样做,并创建自己的组合:

@Composable
fun MyClickableText(
    modifier: Modifier = Modifier,
    text: String,
    clickableParts: Map<String, (String) -> Unit>,
    normalTextSpanStyle: SpanStyle = LocalTextStyle.current.toSpanStyle()
        .copy(color = LocalContentColor.current),
    clickableTextSpanStyle: SpanStyle = normalTextSpanStyle.copy(color = Color.Blue)
) {
    val placeHolderStart = "|_?_|"
    val placeHolderEnd = "_|?|_"
    var markedText = text
    clickableParts.keys.forEach {
        markedText = markedText.replace(it, "$placeHolderStart$it$placeHolderEnd")
    }
    val splitString = markedText.split(placeHolderStart)
    val annotatedString = buildAnnotatedString {
        splitString.forEach { s ->
            val parts = s.split(placeHolderEnd)
            if (parts.size <= 1) {
                withStyle(style = normalTextSpanStyle) {
                    append(parts.first())
                }
                return@forEach
            }
            withStyle(style = clickableTextSpanStyle) {
                pushStringAnnotation(tag = parts.first(), annotation = parts.first())
                append(parts.first())
            }
            withStyle(style = normalTextSpanStyle) {
                append(parts[1])
            }
        }
    }
    ClickableText(
        modifier = modifier,
        text = annotatedString,
        style = MaterialTheme.typography.bodyMedium,
        onClick = { offset ->
            annotatedString.getStringAnnotations(offset, offset)
                .firstOrNull()?.let { span ->
                    clickableParts[span.tag]?.invoke(span.tag)
                }
        })
}

然后,无论何时你需要,只要打电话,比如:

MyClickableText(
            modifier = Modifier.padding(top = MaterialTheme.spacing.small),
            text = TextResource.StringResource(
                R.string.click_to_add_a_note, stringResource(
                    id = R.string.link_alias_to_add_a_note
                )
            ).asString(),
            clickableParts = mapOf(Pair(stringResource(id = R.string.link_alias_to_add_a_note)) {
                onAddClicked()
            })
        )

有了它,你将能够告诉你想要点击的单词/句子,以及点击时它应该调用的操作。

希望有帮助。

相关问题