如何在 Jetpack Compose 中单击某个单词(如 Duolingo)时在该单词上方显示工具提示

问题描述 投票:0回答:1

我正在尝试向我的 Jetpack Compose 应用程序添加一项功能,当用户单击某个单词时,工具提示将出现在该单词的上方/下方,类似于 Duolingo:

到目前为止,我有一个 AnnotatedString,它可以在单击时打印单词。以下是我在给定输入字符串的情况下生成 AnnotatedString 的方法:

val input = // get some string input from user
val words = input.parseInput() // split a String into a list of words and spaces (e.g. "Hello world" -> ["Hello", " ", "world"])
data class AnnotatedWord(word: String,  tag: String)
val annotatedWords = emptyList<AnnotatedWord>()
var wordIndex = 0
val annotatedString = buildAnnotatedString {
    words.forEach { word ->
        if (word == " ") {
            append(word)
            continue
        }
        val tag = "${word}:${wordIndex++}"
        pushStringAnnotation(tag = tag, annotation = tag)
        withStyle(style = SpanStyle(textDecoration = TextDecoration.Underline)) {
            append(word)
        }
        pop()
        annotatedWords.add(AnnotatedWord(word, tag))
    }
}

这是我使用点击侦听器显示它的方式:

ClickableText(
    text = annotatedString,
    onClick = { index ->
        val annotation = annotatedString.getStringAnnotations(start = index, end = index).firstOrNull()
        if (annotation != null) {
            val tag = annotation.tag
            val matchingWord = annotatedWords.find { it.tag == tag }
            print(matchingWord.word)
        }
    }
)

这效果很好 - 它给了我一个字符串,其中每个单词都带有下划线,然后单击一个单词即可打印它。然而我在工具提示部分遇到了困难。我想我可以通过将 ClickableText 嵌套在 Box 中,将工具提示也放入该 Box 中,并使用 Modifier.offset() 将其放置在单词上方来显示工具提示。但是,我不确定如何获取此偏移量,更不用说如何将其从 AnnotatedString 传递到我的可组合项了。

android android-jetpack-compose
1个回答
0
投票

我最终这样做了:

  1. 将工具提示和文本放入框中
  2. 在 Text.onTextLayout 中,像这样获取偏移量:
// index = the index of the clicked character in the string
val wordBoundary = layoutResult.getWordBoundary(index)
val leftBox = layoutResult.getBoundingBox(wordBoundary.min)
val rightBox = layoutResult.getBoundingBox(wordBoundary.max - 1)
val middle = (leftBox.left + rightBox.right) / 2
val top = leftBox.top
val offset = Offset(x = middle, y = top)
  1. 在 Tooltip 的 Modifier.layout 中,将工具提示定位如下:
val placeable = measurable.measure(constraints)
val width = placeable.width
val height = placeable.height
// set width/height to 0 so the tooltip doesn't take up any space in its container
layout(0, 0) {
    val x = (offset.x - (width / 2)).toInt()
    val y = (offset.y - height).toInt()
    placeable.placeRelative(x, y)
}

最终看起来像这样:

tooltip displayed over word

© www.soinside.com 2019 - 2024. All rights reserved.