gpt4 book ai didi

android - 如何使用 Jetpack Compose 在文本中制作中间省略号

转载 作者:行者123 更新时间:2023-12-04 23:41:50 31 4
gpt4 key购买 nike

我需要在 Jetpack Compose Text 中制作中间省略号。据我所知,TextOverflow 只有 Clip、Ellipsis 和 Visible 选项。
像这样:4gh45g43h...bh4bh6b64

最佳答案

暂未官方支持,敬请关注this issue .
目前,您可以使用以下方法。我用 SubcomposeLayout获取 onTextLayout结果没有实际绘制初始文本。
需要大量代码和计算才能:

  • 考虑到应用于文本的所有修饰符,请确保省略号是必要的。
  • 根据字符的大小,而不仅仅是字符的数量,使左右部分的大小尽可能接近。

  • @Composable
    fun MiddleEllipsisText(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Unspecified,
    softWrap: Boolean = true,
    onTextLayout: (TextLayoutResult) -> Unit = {},
    style: TextStyle = LocalTextStyle.current,
    ) {
    // some letters, like "r", will have less width when placed right before "."
    // adding a space to prevent such case
    val layoutText = remember(text) { "$text $ellipsisText" }
    val textLayoutResultState = remember(layoutText) {
    mutableStateOf<TextLayoutResult?>(null)
    }
    SubcomposeLayout(modifier) { constraints ->
    // result is ignored - we only need to fill our textLayoutResult
    subcompose("measure") {
    Text(
    text = layoutText,
    color = color,
    fontSize = fontSize,
    fontStyle = fontStyle,
    fontWeight = fontWeight,
    fontFamily = fontFamily,
    letterSpacing = letterSpacing,
    textDecoration = textDecoration,
    textAlign = textAlign,
    lineHeight = lineHeight,
    softWrap = softWrap,
    maxLines = 1,
    onTextLayout = { textLayoutResultState.value = it },
    style = style,
    )
    }.first().measure(Constraints())
    // to allow smart cast
    val textLayoutResult = textLayoutResultState.value
    ?: // shouldn't happen - onTextLayout is called before subcompose finishes
    return@SubcomposeLayout layout(0, 0) {}
    val placeable = subcompose("visible") {
    val finalText = remember(text, textLayoutResult, constraints.maxWidth) {
    if (text.isEmpty() || textLayoutResult.getBoundingBox(text.indices.last).right <= constraints.maxWidth) {
    // text not including ellipsis fits on the first line.
    return@remember text
    }

    val ellipsisWidth = layoutText.indices.toList()
    .takeLast(ellipsisCharactersCount)
    .let widthLet@{ indices ->
    // fix this bug: https://issuetracker.google.com/issues/197146630
    // in this case width is invalid
    for (i in indices) {
    val width = textLayoutResult.getBoundingBox(i).width
    if (width > 0) {
    return@widthLet width * ellipsisCharactersCount
    }
    }
    // this should not happen, because
    // this error occurs only for the last character in the string
    throw IllegalStateException("all ellipsis chars have invalid width")
    }
    val availableWidth = constraints.maxWidth - ellipsisWidth
    val startCounter = BoundCounter(text, textLayoutResult) { it }
    val endCounter = BoundCounter(text, textLayoutResult) { text.indices.last - it }

    while (availableWidth - startCounter.width - endCounter.width > 0) {
    val possibleEndWidth = endCounter.widthWithNextChar()
    if (
    startCounter.width >= possibleEndWidth
    && availableWidth - startCounter.width - possibleEndWidth >= 0
    ) {
    endCounter.addNextChar()
    } else if (availableWidth - startCounter.widthWithNextChar() - endCounter.width >= 0) {
    startCounter.addNextChar()
    } else {
    break
    }
    }
    startCounter.string.trimEnd() + ellipsisText + endCounter.string.reversed().trimStart()
    }
    Text(
    text = finalText,
    color = color,
    fontSize = fontSize,
    fontStyle = fontStyle,
    fontWeight = fontWeight,
    fontFamily = fontFamily,
    letterSpacing = letterSpacing,
    textDecoration = textDecoration,
    textAlign = textAlign,
    lineHeight = lineHeight,
    softWrap = softWrap,
    onTextLayout = onTextLayout,
    style = style,
    )
    }[0].measure(constraints)
    layout(placeable.width, placeable.height) {
    placeable.place(0, 0)
    }
    }
    }

    private const val ellipsisCharactersCount = 3
    private const val ellipsisCharacter = '.'
    private val ellipsisText = List(ellipsisCharactersCount) { ellipsisCharacter }.joinToString(separator = "")

    private class BoundCounter(
    private val text: String,
    private val textLayoutResult: TextLayoutResult,
    private val charPosition: (Int) -> Int,
    ) {
    var string = ""
    private set
    var width = 0f
    private set

    private var _nextCharWidth: Float? = null
    private var invalidCharsCount = 0

    fun widthWithNextChar(): Float =
    width + nextCharWidth()

    private fun nextCharWidth(): Float =
    _nextCharWidth ?: run {
    var boundingBox: Rect
    // invalidCharsCount fixes this bug: https://issuetracker.google.com/issues/197146630
    invalidCharsCount--
    do {
    boundingBox = textLayoutResult
    .getBoundingBox(charPosition(string.count() + ++invalidCharsCount))
    } while (boundingBox.right == 0f)
    _nextCharWidth = boundingBox.width
    boundingBox.width
    }

    fun addNextChar() {
    string += text[charPosition(string.count())]
    width += nextCharWidth()
    _nextCharWidth = null
    }
    }
    我的测试代码:
    val text = remember { LoremIpsum(100).values.first().replace("\n", " ") }
    var length by remember { mutableStateOf(77) }
    var width by remember { mutableStateOf(0.5f) }
    Column {
    MiddleEllipsisText(
    text.take(length),
    fontSize = 30.sp,
    modifier = Modifier
    .background(Color.LightGray)
    .padding(10.dp)
    .fillMaxWidth(width)
    )
    Slider(
    value = length.toFloat(),
    onValueChange = { length = it.roundToInt() },
    valueRange = 2f..text.length.toFloat()
    )
    Slider(
    value = width,
    onValueChange = { width = it },
    )
    }
    结果:

    关于android - 如何使用 Jetpack Compose 在文本中制作中间省略号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69083061/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com