Я пытался получить текст с реальными границами, работая в Jetpack Compose.
Я попробовал использовать стиль тени в композиции Text
, но он не работает и выглядит не очень хорошо.
Text(
text = "lorem ipsum",
style = TextStyle(shadow = Shadow(color = borderColor, blurRadius = 7.5f)),
)
использование тени приводит к чему-то вроде этого
но то, что мне нужно, должно быть больше похоже на это
Только обрисовывание текста можно выполнить с помощью другого DrawStyle
:
Text(
text = "lorem ipsum",
style = TextStyle(
color = borderColor,
drawStyle = Stroke(),
),
)
Для Stroke
доступны различные настройки, взгляните на его параметры.
Однако при этом будет нарисован только контур, внутренняя часть останется пустой, а вместо нее будет виден фон. Я не думаю, что есть встроенный способ наполнить интерьер. В качестве обходного пути вы можете нарисовать текст дважды: сначала только с контуром, а затем поверх обычного заполненного текста:
@ExperimentalComposeUiApi
@Composable
fun OutlinedText(
text: String,
modifier: Modifier = Modifier,
fillColor: Color = Color.Unspecified,
outlineColor: Color,
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,
overflow: TextOverflow = TextOverflow.Clip,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
minLines: Int = 1,
onTextLayout: (TextLayoutResult) -> Unit = {},
style: TextStyle = LocalTextStyle.current,
outlineDrawStyle: Stroke = Stroke(),
) {
Box(modifier = modifier) {
Text(
text = text,
modifier = Modifier.semantics { invisibleToUser() },
color = outlineColor,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = null,
textAlign = textAlign,
lineHeight = lineHeight,
overflow = overflow,
softWrap = softWrap,
maxLines = maxLines,
minLines = minLines,
onTextLayout = onTextLayout,
style = style.copy(
shadow = null,
drawStyle = outlineDrawStyle,
),
)
Text(
text = text,
color = fillColor,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
overflow = overflow,
softWrap = softWrap,
maxLines = maxLines,
minLines = minLines,
onTextLayout = onTextLayout,
style = style,
)
}
}
Теперь вы можете просто использовать это:
OutlinedText(
text = "lorem ipsum",
outlineColor = borderColor,
)
Настройку обводки контура можно задать с помощью необязательного параметра outlineDrawStyle
, цвет заливки можно указать с помощью fillColor
.
Этот новый OutlinedText
должен работать так же, как обычный текст, поэтому вы также можете использовать все остальные параметры, даже параметр style
. Я не уверен, насколько надежно он будет обрабатывать параметр modifier
, но могу представить некоторые крайние случаи, когда он будет вести себя по-другому.
Чтобы учесть изменение семантики (поскольку теперь есть два текста, даже если он выглядит только как один), я скрыл второй текст из дерева семантики. Это необходимо для обеспечения доступности (чтения экрана/TalkBack), инструментальных тестов и т. д., но на самом деле я не проверял его поведение.
Вы правы, вероятно, лучше, чтобы заполненный текст находился поверх контура, если обводка контура более толстая. Я обновил ответ соответственно.
изменение порядка, в котором тексты отображались фиксированными, создает идеальную копию того, что я хочу