Jetpack Compose, центрирование текста без заполнения шрифта?

Я борюсь с вертикальным центрированием текста в Jetpack Compose. Похоже, что в моем шрифте много отступов, и я не могу найти способ отключить его. Это произошло только один раз , прежде чем на SO, насколько я могу судить, здесь , но их ответ , используя раскладку ограничения позволяет предположить , что они просто позиционировали его абсолютно, что это не совсем подходит так же , как обходной путь, и чего-то я бы хотел избежать.

Это хорошо видно на скриншоте ниже.

Код для этого выглядит так:

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

Аргументы, которые вы ожидаете от него, - verticalArrangement и textAlign - здесь ничего не делайте, но я включаю их, чтобы продемонстрировать, что я пробовал.

Мой обходной путь до сих пор заключался в использовании Modifier.graphicsLayer(translationY = -25f)сдвинуть его вверх, но это кажется ужасным взломом для чего-то, что должно быть настолько простым. Похоже, что в классических макетах Android можно было установить android:includeFontPadding="false" и это бы обошло это поведение, но похоже, что в Jetpack Compose нет аналогичной опции.

Кто-нибудь сталкивался с этим?

6 ответов

Это происходит из-за неравномерного заполнения шрифта на https://fonts.google.com/specimen/Oswald , а текст, который вы используете в нижнем регистре, делает несоответствие более очевидным.

Как упоминалось ниже @Siyamed, API для отключения поведения includeFontPadding по умолчанию в Compose был выпущен с бета-версией Compose 1.2, и вы используете его следующим образом:

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

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

попробуй, может поможет? Кстати, тот факт, что PlatformTextStyle «устарел», просто хочет сообщить, что это API совместимости.

Согласно https://issuetracker.google.com/issues/171394808, похоже, это одно из ограничений текущего JetPack Compose.

Это также мешает моему приложению, потому что используемый шрифт в значительной степени зависит от includeFontPadding. Для текущего обходного пути я создаю CoreText, который обертывает TextView внутри моей композиции.

Вот пример моей оболочки, она не идеальна, но выполняет свою работу для моего текущего варианта использования:

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

ИспользуяCompose 1.2.0-alpha07и выше, вы можете использоватьPlatformTextStyleAPI для установкиincludeFontPadding.

Попробуйте следующий код:

      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
        )
    /* ... */
    )
)

Результат, когда includeFontPadding = false:

Результат, когда includeFontPadding = trueили не использовать его:

Больше информации:

Исправление отступов шрифта в Compose Text — Medium

Просто обошел ту же проблему.

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

В Compose теперь есть TextStyle.platformStyle.incudeFontPadding, для которого по умолчанию установлено значение true для версии 1.2. вы можете установить для него значение false в своем TextStyle

Сделать значение по умолчанию ложным — это то, что Compose хочет сделать в версии 1.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)
    }
}
Другие вопросы по тегам