简体   繁体   English

Jetpack Compose,没有字体填充的居中文本?

[英]Jetpack Compose, centering text without font padding?

I'm struggling with vertically centering text in Jetpack Compose version alpha-11.我在 Jetpack Compose alpha-11 版中遇到垂直居中文本问题。 It appears that my font has a significant amount of padding and I'm unable to find a way to disable it.看来我的字体有大量填充,我无法找到禁用它的方法。 This has come up only once before on SO, as far as I can tell, here , but their answer of using a constraint layout seems to suggest that they simply positioned it absolutely, which isn't exactly a solution as much as a workaround, and something I'd like to avoid.据我所知, 在 SO 之前只出现过一次,但是他们对使用约束布局的回答似乎表明他们只是将其绝对定位,这与其说是一种解决方案,不如说是一种解决方案,和我想避免的事情。

You can see it clearly in the screenshot below.您可以在下面的屏幕截图中清楚地看到它。

在此处输入图像描述

The code for that looks like this:代码如下所示:

                   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)
                        )
                    }

The arguments you would expect to position it -- verticalArrangement and textAlign -- do not do anything here but I'm including them to demonstrate what I've tried.您期望的 arguments 到 position 它 -- verticalArrangementtextAlign -- 在这里不执行任何操作,但我将它们包括在内以演示我的尝试。

My workaround so far has been to use Modifier.graphicsLayer(translationY = -25f) to shift it up but that seems like a terrible hack for something that should be so straightforward.到目前为止,我的解决方法是使用Modifier.graphicsLayer(translationY = -25f)将其向上移动,但这对于本应如此简单的事情来说似乎是一个可怕的 hack。 It appears that in classic Android layouts, one could set android:includeFontPadding="false" and that would bypass this behavior but there doesn't seem to be a similar option in Jetpack Compose.似乎在经典的 Android 布局中,可以设置android:includeFontPadding="false"并绕过此行为,但 Jetpack Compose 中似乎没有类似的选项。

Anyone encounter this?有人遇到过这个吗?

According to https://issuetracker.google.com/issues/171394808 , It seems this is one of the limitations of the current JetPack Compose.根据https://issuetracker.google.com/issues/171394808 ,这似乎是当前 JetPack Compose 的限制之一。

This is also deal breaker for my app because the font used rely heavily with the includeFontPadding .这也是我的应用程序的交易破坏者,因为使用的字体严重依赖于includeFontPadding For current workaround, I create a CoreText that wraps TextView inside my compose.对于当前的解决方法,我创建了一个 CoreText,它将 TextView 包装在我的 compose 中。

Here's example of my wrapper, its not perfect but it does the job for my current use case:这是我的包装器的示例,它并不完美,但它可以满足我当前的用例:

@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
    }
}

Just got around this same issue.刚刚解决了同样的问题。

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

(Temporary) custom solution: (临时)定制解决方案:

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)
    }
}

Compose now have TextStyle.platformStyle.incudeFontPadding that is set to true by default for version 1.2. Compose 现在将 TextStyle.platformStyle.incudeFontPadding 在 1.2 版中默认设置为 true。 you can set it to false in your TextStyle您可以在 TextStyle 中将其设置为 false

Making the default false is something that Compose wants to do in v1.3 or later.将默认设置设为 false 是 Compose 在 v1.3 或更高版本中想要做的事情。

This happens due to uneven font padding on https://fonts.google.com/specimen/Oswald , plus the text you're using in lowercase makes the discrepancy more obvious.这是由于https://fonts.google.com/specimen/Oswald上的字体填充不均匀,加上您使用的小写文本使差异更加明显。

As @Siyamed mentioned below, the API to turn the default includeFontPadding behaviour off in Compose was released with Compose 1.2 beta and you use it like so:正如@Siyamed 下面提到的,API 在 Compose 中关闭默认 includeFontPadding 行为是随 Compose 1.2 beta 一起发布的,您可以像这样使用它:

Text(
...
   textStyle = TextStyle(
      platformStyle = PlatformTextStyle(
     includeFontPadding = false
   ),
)

https://android-developers.googleblog.com/2022/05/whats-new-in-jetpack-compose.html https://android-developers.googleblog.com/2022/05/whats-new-in-jetpack-compose.html

give it a try, might help?试一试,可能有帮助吗?

By using Compose 1.2.0-alpha07 and above, you can use PlatformTextStyle api to set includeFontPadding .通过使用Compose 1.2.0-alpha07及以上版本,您可以使用PlatformTextStyle api 来设置includeFontPadding

Try to the below code:尝试以下代码:

private val NotoSans = FontFamily(
    Font(R.font.noto_san_jp_black, FontWeight.Black),
    Font(R.font.noto_san_jp_light, FontWeight.Light),
    Font(R.font.noto_san_jp_bold, FontWeight.Bold),
    Font(R.font.noto_san_jp_thin, FontWeight.Thin),
    Font(R.font.noto_san_jp_medium, FontWeight.Medium),
    Font(R.font.noto_san_jp_regular, FontWeight.Normal),
)

val Typography = Typography(
    headlineLarge = Typography().headlineLarge.copy(
        fontFamily = NotoSans,
    )
)

@OptIn(ExperimentalTextApi::class)
/* ... */

Text(
    text = "地域のお得は\nすべてここに",
    style = MaterialTheme.typography.headlineLarge.copy(
        platformStyle = PlatformTextStyle(
            includeFontPadding = false
        )
    /* ... */
    )
)

The result when includeFontPadding = false : includeFontPadding = false时的结果:

includeFontPadding = false

The result when includeFontPadding = true or no using it: includeFontPadding = true或不使用时的结果:

includeFontPadding = true 或不使用

More information:更多信息:

Fixing Font Padding in Compose Text - Medium 修复撰写文本中的字体填充 - Medium

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM