Текст с обводкой или границами в наборе реактивного ранца

Я пытался получить текст с реальными границами, работая в Jetpack Compose.

Я попробовал использовать стиль тени в композиции Text, но он не работает и выглядит не очень хорошо.

Text(
     text = "lorem ipsum",
     style = TextStyle(shadow = Shadow(color = borderColor, blurRadius = 7.5f)),
)

использование тени приводит к чему-то вроде этого

но то, что мне нужно, должно быть больше похоже на это

1
0
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Только обрисовывание текста можно выполнить с помощью другого 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), инструментальных тестов и т. д., но на самом деле я не проверял его поведение.

изменение порядка, в котором тексты отображались фиксированными, создает идеальную копию того, что я хочу

Abdallah Mehiz 23.06.2024 14:52

Вы правы, вероятно, лучше, чтобы заполненный текст находился поверх контура, если обводка контура более толстая. Я обновил ответ соответственно.

Leviathan 23.06.2024 19:18

Другие вопросы по теме

Ошибка Kotlin: java.lang.RuntimeException: не удалось найти реализацию для com.example.tutorialfollowing.AppDatabase. AppDatabase_Impl не существует
Ошибка размера анимированной бутылки с водой при составлении реактивного ранца
Рукоять кинжала: «Невозможно создать экземпляр ViewModel» при использовании внедрения зависимостей
Невозможно получить доступ к классу Retrofit2.Response. Проверьте путь к классам вашего модуля на предмет отсутствующих или конфликтующих зависимостей
Как я могу проверить, реализует ли класс интерфейс в Котлине?
Как передать строковый параметр в модель представления в составлении?
Как создать построитель шагов в Kotlin, который поддерживает повторяемые шаги
Как вызвать приостановку развлечения асинхронно из области потока?
Изображение не отображается с помощью RememberAsyncImagePainter Coil
Предупреждение Play Console: обновите зависимость Play Core Maven до версии, совместимой с Android 14