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
и выше, вы можете использоватьPlatformTextStyle
API для установки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
или не использовать его:
Больше информации:
Просто обошел ту же проблему.
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)
}
}