【问题标题】:Jetpack Compose, centering text without font padding?Jetpack Compose,没有字体填充的居中文本?
【发布时间】:2021-02-09 20:23:50
【问题描述】:

我在 Jetpack Compose 版本 alpha-11 中遇到垂直居中文本问题。看来我的字体有大量填充,我无法找到禁用它的方法。据我所知,这在 SO 上只出现过一次,@ 987654321@,但他们使用约束布局的答案似乎表明他们只是将它绝对定位,这并不完全是一个解决方案解决方法,以及我想避免的事情。

您可以在下面的屏幕截图中清楚地看到它。

代码如下:

                   Column(verticalArrangement = Arrangement.Center) {
                        Text(
                            text = "Let's Go",
                            color = Color.White,
                            fontSize = 120.sp,
                            fontFamily = oswaldLightFontFamily(),
                            textAlign = TextAlign.Center,
                            modifier = Modifier.background(Color.Blue)
                        )
                    }

您希望将其定位的参数 -- verticalArrangementtextAlign -- 在这里没有做任何事情,但我将它们包括在内以展示我已经尝试过的内容。

到目前为止,我的解决方法是使用Modifier.graphicsLayer(translationY = -25f) 将其向上移动,但这对于应该如此简单的事情来说似乎是一个可怕的黑客攻击。似乎在经典的 Android 布局中,可以设置 android:includeFontPadding="false" 并且可以绕过这种行为,但在 Jetpack Compose 中似乎没有类似的选项。

有人遇到过吗?

【问题讨论】:

  • -25f 是否适用于该字体的所有设备,或者需要一个密度乘数才能使其在所有设备上“类似”地工作?
  • Tbh 我还没有在其他设备上尝试过,我只需要针对具有特定分辨率的特定设备就被宠坏了。不过,我希望需要对其进行调整,以便它在其他设备上正常工作。我对 Android 没有足够的经验来提供建议,这正是我在 CSS 中处理此类事情的方式。另请注意,-25f 通常只是一个起点,我已经根据需要进行了微调。我也希望其他字体有所不同。这一切都感觉很hacky,我希望尽快有更好的解决方案!
  • issuetracker.google.com/issues/171394808#comment24 这个变通方法效果很好。

标签: android android-jetpack-compose


【解决方案1】:

根据https://issuetracker.google.com/issues/171394808,这似乎是当前JetPack Compose的限制之一。

这也是我的应用程序的交易破坏者,因为使用的字体严重依赖includeFontPadding。对于当前的解决方法,我创建了一个 CoreText,将 TextView 包装在我的 compose 中。

这是我的包装器的示例,它并不完美,但它适用于我当前的用例:

@Composable
fun CoreText(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    overflow: TextOverflow = TextOverflow.Clip,
    maxLines: Int = Int.MAX_VALUE,
    style: TextStyle = Typography.body2,
    onClick: (() -> Unit)? = null,
) {
    AndroidView(
        modifier = modifier,
        factory = { context ->
            TextView(context)
        },
        update = {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                it.setTextAppearance(style.fontWeight.toStyle())
            } else {
                it.setTextAppearance(it.context, style.fontWeight.toStyle())
            }

            if (overflow == TextOverflow.Ellipsis) {
                it.ellipsize = TextUtils.TruncateAt.END
            }

            if (textDecoration != null) {
                it.paintFlags = when (textDecoration) {
                    TextDecoration.Underline -> {
                        Paint.UNDERLINE_TEXT_FLAG
                    }
                    TextDecoration.LineThrough -> {
                        Paint.STRIKE_THRU_TEXT_FLAG
                    }
                    else -> 0
                }
            }

            if (onClick != null) {
                it.setOnClickListener { onClick.invoke() }
            }

            if (color != Color.Unspecified || style.color != Color.Unspecified) {
                it.setTextColor(if (color == Color.Unspecified) style.color.toArgb() else color.toArgb())
            }

            it.textSize = style.fontSize.value
            it.text = text
            it.background = ColorDrawable(style.background.toArgb())
            it.maxLines = maxLines
            it.includeFontPadding = false
            it.textAlignment = textAlign?.toStyle() ?: style.textAlign.toStyle()
        }
    )
}

// Replace with your style
fun FontWeight?.toStyle(): Int {
    return when (this) {
        FontWeight.Bold -> R.style.TextStyle_Bold
        FontWeight.Normal -> R.style.TextStyle_Regular
        FontWeight.Medium, FontWeight.SemiBold -> R.style.TextStyle_Medium
        else -> -1
    }
}

fun TextAlign?.toStyle(): Int {
    return when (this) {
        TextAlign.Left -> TEXT_ALIGNMENT_TEXT_START
        TextAlign.Right -> TEXT_ALIGNMENT_TEXT_END
        TextAlign.Center -> TEXT_ALIGNMENT_CENTER
        TextAlign.Start -> TEXT_ALIGNMENT_TEXT_START
        TextAlign.End -> TEXT_ALIGNMENT_TEXT_END
        else -> -1
    }
}

【讨论】:

【解决方案2】:

刚刚解决了同样的问题。

Box(contentAlignment = Alignment.Center){
       Text(
                text = "OK"
                textAlign = TextAlign.Center
        )
}

【讨论】:

  • 你试过了吗?
  • 我不再从事这个项目了,所以很遗憾没有:-(
  • 我有。将其标记为答案!
  • 好吧,开个玩笑。这确实有效,正如 Alignment.Center 参数所清楚的那样,其功能与名称所暗示的相同
  • @MARSK 您是否使用了带有自定义填充的自定义字体?它仅适用于没有自定义填充的默认 Roboto 字体
【解决方案3】:

(临时)自定义解决方案:

fun Modifier.baselinePadding(
    firstBaselineToTop: Dp,
    lastBaselineToBottom: Dp
) = layout { measurable, constraints ->
    val placeable = measurable.measure(constraints)

    check(placeable[FirstBaseline] != AlignmentLine.Unspecified)
    val firstBaseline = placeable[FirstBaseline]

    check(placeable[LastBaseline] != AlignmentLine.Unspecified)
    val lastBaseline = placeable[LastBaseline]

    val lastBaselineToBottomHeight = placeable.height - lastBaseline

    val lastBaselineToBottomDelta = lastBaselineToBottom.roundToPx() - lastBaselineToBottomHeight

    val totalHeight = placeable.height +
            (firstBaselineToTop.roundToPx() - firstBaseline)

    val placeableY = totalHeight - placeable.height
    layout(placeable.width, totalHeight + lastBaselineToBottomDelta) {
        placeable.placeRelative(0, placeableY)
    }
}

【讨论】:

  • 这如何让您将文本居中?看起来它只是让您将填充设置为顶部/底部基线,但无法知道使用多少填充来使文本在视觉上居中
猜你喜欢
  • 2020-12-22
  • 1970-01-01
  • 1970-01-01
  • 2022-10-22
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-05
相关资源
最近更新 更多