Jetpack Compose - 文本字段省略号

发布于 01-20 21:50 字数 296 浏览 4 评论 0原文

我正在尝试在 Jetpack Compose 中创建单行文本输入。

由于此输入的固定宽度应为 200.dp 并且只有一行,因此较长的文本将被截断。有时,被剪切的文本看起来甚至不存在,因为剪切是在两个字母之间进行的。为了向用户显示已经输入了“更多”文本,我更喜欢省略号(例如,这是一个示例输入...)效果。

我尝试使用默认的 TextFieldBasicTextField 可组合项,但似乎没有简单的解决方案。

有没有办法在 Jetpack Compose 中创建这种省略号效果?

I am trying to create a single line text input in Jetpack Compose.

Since this input should have a fix width of 200.dp and is only one line, longer text is going to be cut off. Sometimes it looks like the cut off text does not even exist because the cut is made between two letters. In order to show the user that there is "more" text already typed I would prefer an ellipsis (e.g. This is a sample inpu...) effect.

I tried to use the default TextField and BasicTextField composables but there seems to be no easy solution.

Is there a way to create this ellipsis effect in Jetpack Compose?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

坐在坟头思考人生2025-01-27 21:50:56

尽管 Brian Ngure 提供的解决方案不起作用,因为错误的偏移会触发崩溃。我用他的想法创建了一个可行的(至少对我来说:D)。

VisualTransformation { text ->
TransformedText(buildAnnotatedString {
    if (maxSymbols < 3) {
        append(text)
    } else {
        append(text.take(maxSymbols - 3))
        append("...")
    }

}, object : OffsetMapping {
    override fun originalToTransformed(offset: Int): Int {
        return if (maxSymbols < 3) text.length else maxSymbols
    }

    override fun transformedToOriginal(offset: Int): Int {
        return text.length
    }
})

其中 3 == "...".length

为了使其工作,您必须获得可以在屏幕上绘制的 ma​​xSymbols
您可以在 TextField 的 onTextLayout 回调中执行此操作
有现成的变量 didOverflowWidth、didOverflowHeight、hasVisualOverflow

        onTextLayout = { result ->
        isTextOverflow = result.didOverflowWidth
    },

如果这不起作用,您可以获取有关当前文本字段宽度 result.size.width 的信息,并将其与 LocalContext 中的屏幕宽度进行比较.current.resources.displayMetrics.widthPixels 你可以了解何时出现溢出。由于某种原因,专用变量对我不起作用。

当发生溢出时,只需使用另一个变量来记住 maxSymbols

并将此转换应用于 TextField 和装饰框(如果您使用的话)。

var isTextOverflow by remember { mutableStateOf(false) }
var maxSymbols: Int = remember(isTextOverflow) { if (isTextOverflow) text.text.length else 0 }

此外,您可能需要重新创建转换,因为不同的符号具有不同的宽度,并且不同的文本宽度可能不同,但过于频繁地重新创建转换可能会降低性能。

更新:
您可能还会发现有用的 TextMeasurer 对象,如果您的文本字段不是屏幕宽,它允许您将文本字段宽度与文本宽度进行比较

    val textMeasurer = rememberTextMeasurer()
    val measuredTextWidth = textMeasurer.measure(
    text = text,
    style = textStyle
)

Although the solution provided by Brian Ngure is not working, because wrong offsets trigger crashes. I used his idea to create a working one (at least for me :D).

VisualTransformation { text ->
TransformedText(buildAnnotatedString {
    if (maxSymbols < 3) {
        append(text)
    } else {
        append(text.take(maxSymbols - 3))
        append("...")
    }

}, object : OffsetMapping {
    override fun originalToTransformed(offset: Int): Int {
        return if (maxSymbols < 3) text.length else maxSymbols
    }

    override fun transformedToOriginal(offset: Int): Int {
        return text.length
    }
})

Where 3 == "...".length

In order for that to work you have to get maxSymbols that can be drawn on the screen.
You can do that in the onTextLayout callback of the TextField
There are ready to use variables didOverflowWidth, didOverflowHeight, hasVisualOverflow

        onTextLayout = { result ->
        isTextOverflow = result.didOverflowWidth
    },

If that's not working, you can get information about current text field width result.size.width and by comparing that with the screen width from LocalContext.current.resources.displayMetrics.widthPixels you can understand when there is an overflow. For some reason the dedicated variables are not working for me.

When the overflow happens, just use another variable to remember maxSymbols

and apply this transformation to the TextField and a decoration box, if you use one.

var isTextOverflow by remember { mutableStateOf(false) }
var maxSymbols: Int = remember(isTextOverflow) { if (isTextOverflow) text.text.length else 0 }

And also you might need to recreate the transformation as different symbols have different width and for different texts width might be different, but recreating transformation too often can be bad for performance.

Update:
You might also find useful a TextMeasurer object that allows you to compare textField width with the text width if your textfield is not screen wide

    val textMeasurer = rememberTextMeasurer()
    val measuredTextWidth = textMeasurer.measure(
    text = text,
    style = textStyle
)
她如夕阳2025-01-27 21:50:56

我意识到这已经很老了,但我也面临着同样的困境。这是我的解决方案。

@Composable
fun ellipsisVisualTransformation() = VisualTransformation { text ->
    val ellipsis = "..."
    val maxLength = 20 // Set your desired max length

    if (text.length <= maxLength) {
        TransformedText(text = text, offsetMapping = OffsetMapping.Identity)
    } else {
        TransformedText(
            AnnotatedString.Builder().apply {
                append(text.take(maxLength - ellipsis.length))
                append(ellipsis)
            }.toAnnotatedString(),
            OffsetMapping.Identity
        )
    }
}

在我的 OutlinedTextField 中,我添加了以下内容:

visualTransformation = ellipsisVisualTransformation()

I realise this is old, but I faced the same predicament. This is my solution.

@Composable
fun ellipsisVisualTransformation() = VisualTransformation { text ->
    val ellipsis = "..."
    val maxLength = 20 // Set your desired max length

    if (text.length <= maxLength) {
        TransformedText(text = text, offsetMapping = OffsetMapping.Identity)
    } else {
        TransformedText(
            AnnotatedString.Builder().apply {
                append(text.take(maxLength - ellipsis.length))
                append(ellipsis)
            }.toAnnotatedString(),
            OffsetMapping.Identity
        )
    }
}

And in my OutlinedTextField, I added this:

visualTransformation = ellipsisVisualTransformation()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文