Compose的文字(十)

本文介绍Jetpack Compose中如何显示与处理文本,包括文本样式设置、字体处理、用户交互等功能,并提供了丰富的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


文字对于软件来说是很重要的,不过本文主要使用起来也比较简单,主要是为了开发时候能够快速复制一下,所以本文主要是源自于Google的教程,几乎没有做修改

Compose 中的文字

文字对任何界面都属于核心内容,而利用 Jetpack Compose 可以更轻松地显示或写入文字。Compose 可以充分利用其构建块的组合,这意味着您无需覆盖各种属性和方法,也无需扩展大型类,即可拥有特定的可组合项设计以及按您期望的方式运行的逻辑。

Compose 提供了基础的 BasicTextBasicTextField,它们是用于显示文字以及处理用户输入的主要函数。Compose 还提供了更高级的 TextTextField,它们是遵循 Material Design 准则的可组合项。建议在 Android 平台上使用这些构建块,因为它们的外观和样式非常适合 Android 用户,而且还包括可用以简化用户自定义设置的其他选项,无需编写大量代码。

显示文字

显示文字的最基本方法是使用以 String 作为参数的 Text 可组合项:

@Composable
fun SimpleText() {
  Text("Hello World")
}

以纯黑色文字显示的“Hello World”字样

显示资源中的文字

我们建议您使用字符串资源,而不是对 Text 值进行硬编码,因为使用字符串资源时您可以与 Android 视图共享相同的字符串,并为您的应用国际化做好准备:

@Composable
fun StringResourceText() {
  Text(stringResource(R.string.hello_world))
}

设置文字样式

Text 可组合项有多个用于为其内容设置样式的可选参数。 以下列出了适用于最常见文字用例的参数。如需查看 Text 的所有参数,建议您查阅 Compose Text 源代码

每当您设置其中任何一个参数,都会将样式应用于整个文字值。如果您需要在同一行或段落中应用多种样式,请参阅有关多种内嵌样式的部分。

更改文字颜色
@Composable
fun BlueText() {
  Text("Hello World", color = Color.Blue)
}

以蓝色文字显示的“Hello World”字样

更改字号
@Composable
fun BigText() {
  Text("Hello World", fontSize = 30.sp)
}

以较大字号显示的“Hello World”字样

将文字设为斜体
@Composable
fun ItalicText() {
  Text("Hello World", fontStyle = FontStyle.Italic)
}

以斜体文字样式显示的“Hello World”字样

将文字设为粗体
@Composable
fun BoldText() {
    Text("Hello World", fontWeight = FontWeight.Bold)
}

以粗体文字样式显示的“Hello World”字样

文字对齐

通过 textAlign 参数,您可以在 Text 可组合项的 Surface 区域内设置文字的对齐方式。

默认情况下,Text 会根据其内容值选择自然的文字对齐方式:

  • 对于从左到右书写的文字,如拉丁语、西里尔文或朝鲜文,向 Text 容器的左边缘对齐
  • 对于从右到左书写的文字,如阿拉伯语或希伯来语,向 Text 容器的右边缘对齐
@Preview(showBackground = true)
@Composable
fun CenterText() {
    Text("Hello World", textAlign = TextAlign.Center,
                modifier = Modifier.width(150.dp))
}

位于容器元素中心的“Hello World”字样

如果您想手动设置 Text 可组合项的文字对齐方式,最好分别使用 TextAlign.StartTextAlign.End(而不要使用 TextAlign.LeftTextAlign.Right),这样系统就可以根据具体语言的首选文字方向,将您的设置解析为向 Text 可组合项的右边缘对齐。例如,TextAlign.End 对于法语文字将向右侧对齐,而对于阿拉伯语文字则将向左侧对齐,但无论对于哪种文字,TextAlign.Right 都将向右侧对齐。

注意:文字对齐与布局对齐不同,后者指的是容器(例如 RowColumn)中的可组合项定位。如需了解详情,请查看 Compose 布局基础知识文档。

不过这种解决方式无法解决垂直居中问题,解决方式参考下述链接:
How to make text centered vertically in Android compose?

字间距和行间距

字间距
UI出图时候字间距一般都会默认为0px,但是在Compose Text中某些关键位置,这种效果会有很明显的问题。下面记录如何修改字间距。
这里提供两种方式

第一种:
 Text(
                modifier = Modifier.padding(0.dp).width(44.dp),
                text = "Content",
                fontSize = 12.sp,
                color = Color(0x99FFFFFF),
                textAlign = TextAlign.Center,
                fontFamily = FontFamily.SansSerif,
                fontWeight = FontWeight.Normal,
                letterSpacing = 0.sp //字符间距为0.sp
            )
第二种:
@Composable
fun MyTextWithLetterSpacing() {
    val letterSpacing = 0.1.sp // 设置字间距
    val text = "Hello, World!"

    val annotatedString = buildAnnotatedString {
        withStyle(style = SpanStyle(letterSpacing = letterSpacing)) {
            append(text)
        }
    }

    Text(
        text = annotatedString,
        color = Color.Black,
        fontSize = 16.sp,
        textAlign = TextAlign.Center,
        modifier = Modifier.padding(16.dp)
    )
}

行间距
行间距一般的话大家都会注意到,因为UI和Compose Text默认的行间距差别挺大的,比较容易发现

@Composable
fun MyTextWithLineHeight() {
    val text = "Hello, World!"
    val lineHeight = 24.sp // 设置行高

    Text(
        text = text,
        color = Color.Black,
        fontSize = 16.sp,
        textAlign = TextAlign.Center,
        modifier = Modifier
            .padding(16.dp)
            .lineHeight(lineHeight)
    )
}
Text的默认边距

和xml中的TextView一样。Compose Text中默认也有空白边距,移除方式如下:

@Composable
fun MyText() {
    Text(
        text = "Hello, World!",
        modifier = Modifier.padding(0.dp)
    )
}

处理字体

Text 有一个 fontFamily 参数,用于设置可组合项中使用的字体。默认情况下,系统会添加 Serif、Sans Serif、等宽和 Cursive 字体系列:

@Composable
fun DifferentFonts() {
    Column {
        Text("Hello World", fontFamily = FontFamily.Serif)
        Text("Hello World", fontFamily = FontFamily.SansSerif)
    }
}

以两种不同字体(使用或不使用 Serif)显示的“Hello World”字样

您可以使用 fontFamily 属性来处理 res/fonts 文件夹中定义的自定义字体和字型:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GUd7eVO9-1626584782384)(https://developer.android.com/images/jetpack/compose/text-font-folder.png)]

以下示例展示了如何根据这些字体文件定义 fontFamily

val firaSansFamily = FontFamily(
        Font(R.font.firasans_light, FontWeight.Light),
        Font(R.font.firasans_regular, FontWeight.Normal),
        Font(R.font.firasans_italic, FontWeight.Normal, FontStyle.Italic),
        Font(R.font.firasans_medium, FontWeight.Medium),
        Font(R.font.firasans_bold, FontWeight.Bold)
)

最后,您可以将此 fontFamily 传递给 Text 可组合项。由于 fontFamily 可以包含不同的粗细度,因此您可以手动设置 fontWeight 来为您的文字选择合适的粗细度:

Column {
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Light)
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Normal)
    Text(
        ..., fontFamily = firaSansFamily, fontWeight = FontWeight.Normal,
        fontStyle = FontStyle.Italic
    )
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Medium)
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Bold)
}

以几种不同文字粗细度和样式显示的“Hello World”字样

如需了解如何在整个应用中设置排版,请参阅主题文档

文字中包含多种样式

如需在同一 Text 可组合项中设置不同的样式,必须使用 AnnotatedString,该字符串可使用任意注解样式加以注解。

AnnotatedString 是一个数据类,其中包含:

  • 一个 Text
  • 一个 SpanStyleRangeList,等同于位置范围在文字值内的内嵌样式
  • 一个 ParagraphStyleRangeList,用于指定文字对齐、文字方向、行高和文字缩进样式

TextStyle 用于 Text 可组合项,而 SpanStyleParagraphStyle 用于 AnnotatedString

SpanStyleParagraphStyle 之间的区别在于,ParagraphStyle 可应用于整个段落,而 SpanStyle 可以在字符级别应用。一旦用 ParagraphStyle 标记了一部分文字,该部分就会与其余部分隔开,就像在开头和末尾有换行符一样。

AnnotatedString 有一个类型安全的构建器,以便您更轻松地创建以下代码:

@Composable
fun MultipleStylesInText() {
    Text(
        buildAnnotatedString {
            withStyle(style = SpanStyle(color = Color.Blue)) {
                append("H")
            }
            append("ello ")

            withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) {
                append("W")
            }
            append("orld")
        }
    )
}

内嵌几种样式变化的“Hello World”字样;H 为蓝色,W 为红色粗体

我们可以按相同的方式设置段落样式:

@Composable
fun paragraphStyle() {
    Text(
        buildAnnotatedString {
            withStyle(style = ParagraphStyle(lineHeight = 30.sp)) {
                withStyle(style = SpanStyle(color = Color.Blue)) {
                    append("Hello\n")
                }
                withStyle(
                    style = SpanStyle(
                        fontWeight = FontWeight.Bold,
                        color = Color.Red
                    )
                ) {
                    append("World\n")
                }
                append("Compose")
            }
        }
    )
}

三个段落采用三种不同的样式:蓝色、红色粗体以及纯黑色

行数上限

如需限制 Text 可组合项中的可见行数,请如如下方式设置 maxLines 参数:

@Composable
fun LongText() {
    Text("hello ".repeat(50), maxLines = 2)
}

一长段文字在显示两行后被截断

文字溢出

在限制长文字时,您可能需要指定文字溢出,这些内容只有在显示的文字被截断时才会显示。如需指定文字溢出,请按如下方式设置 textOverflow 参数:

@Composable
fun OverflowedText() {
    Text("Hello Compose ".repeat(50), maxLines = 2, overflow = TextOverflow.Ellipsis)
}

一长段文字在显示三行后被截断,末尾带有省略号

主题

如需使用应用主题进行文字样式设置,请参阅主题文档

用户互动

Jetpack Compose 支持 Text 中的精细互动。文字选择现在更加灵活,并且可以跨各种可组合项布局进行选择。文字中的用户互动与其他可组合项布局不同,因为您无法为 Text 可组合项的某一部分添加修饰符。本部分将重点介绍支持用户互动的不同 API。

选择文字

默认情况下,可组合项不可选择,这意味着在默认情况下用户无法从您的应用中选择和复制文字。要启用文字选择,需要使用 SelectionContainer 可组合项封装文字元素:

@Composable
fun SelectableText() {
    SelectionContainer {
        Text("This text is selectable")
    }
}

用户选定了一个简短的文字段落。

您可能想为可选择区域的特定部分停用选择功能。如果要执行此操作,您需要使用 DisableSelection 可组合项来封装不可选择的部分:

@Composable
fun PartiallySelectableText() {
    SelectionContainer {
        Column {
            Text("This text is selectable")
            Text("This one too")
            Text("This one as well")
            DisableSelection {
                Text("But not this one")
                Text("Neither this one")
            }
            Text("But again, you can select this one")
            Text("And this one too")
        }
    }
}

一个较长的文字段落。用户尝试选中整个段落,但由于有两行内容应用了 DisableSelection,所以这两行无法选中。

获取点击文字的位置

如需监听 Text 的点击次数,您可以添加 clickable 修饰符。不过,如果您想在 Text 可组合项内获取点击位置,在对文字的不同部分执行不同操作的情况下,您需要改用 ClickableText

@Composable
fun SimpleClickableText() {
    ClickableText(
        text = AnnotatedString("Click Me"),
        onClick = { offset ->
            Log.d("ClickableText", "$offset -th character is clicked.")
        }
    )
}
点击注解

当用户点击 Text 可组合项时,您可能想向 Text 值的某一部分附加额外信息,例如向特定字词附加可在浏览器中打开的网址。如果要执行此操作,您需要附加一个注解,用于获取一个标记 (String)、一个项 (String) 和一个文字范围作为参数。在 AnnotatedString 中,这些注解可以按照其标记或文字范围进行过滤。示例如下:

@Composable
fun AnnotatedClickableText() {
    val annotatedText = buildAnnotatedString {
        append("Click ")

        // We attach this *URL* annotation to the following content
        // until `pop()` is called
        pushStringAnnotation(tag = "URL",
                             annotation = "https://developer.android.com")
        withStyle(style = SpanStyle(color = Color.Blue,
                                    fontWeight = FontWeight.Bold)) {
            append("here")
        }

        pop()
    }

    ClickableText(
        text = annotatedText,
        onClick = { offset ->
            // We check if there is an *URL* annotation attached to the text
            // at the clicked position
            annotatedText.getStringAnnotations(tag = "URL", start = offset,
                                                    end = offset)
                .firstOrNull()?.let { annotation ->
                    // If yes, we log its value
                    Log.d("Clicked URL", annotation.item)
                }
        }
    )
}

输入和修改文字

TextField 允许用户输入和修改文字。TextField 实现分为两个级别:

  1. TextField
    

    是 Material Design 实现。我们建议您选择此实现,因为它遵循的是

    Material Design 指南

    • 默认样式为填充
    • OutlinedTextField轮廓样式版本
  2. BasicTextField 允许用户通过硬件或软件键盘编辑文字,但没有提供提示或占位符等装饰。

@Composable
fun SimpleFilledTextFieldSample() {
    var text by remember { mutableStateOf("Hello") }

    TextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

包含“Hello”字样的可编辑文字字段。该字段含有不可编辑的“label”标签。

@Composable
fun SimpleOutlinedTextFieldSample() {
    var text by remember { mutableStateOf("") }

    OutlinedTextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

可编辑的文字字段,带有紫色边框和标签。

设置 TextField 样式

TextFieldBasicTextField 共用许多可对它们进行自定义的常用参数。如需查看 TextField 的完整列表,请参阅 TextField 源代码。以下列出了部分有用的参数,但并非详尽无遗:

  • singleLine
  • maxLines
  • textStyle
@Composable
fun StyledTextField() {
    var value by remember { mutableStateOf("Hello\nWorld\nInvisible") }

    TextField(
        value = value,
        onValueChange = { value = it },
        label = { Text("Enter text") },
        maxLines = 2,
        textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
        modifier = Modifier.padding(20.dp)
    )
}

多行 TextField,包括两个可编辑的行以及标签

如果您的设计调用 Material TextField 或 OutlineTextField,建议您使用 TextField 而不是 BasicTextField。但是,在构建无需 Material 规范中的装饰的设计时,应使用 BasicTextField

键盘选项

借助 TextField,您可以设置键盘配置选项(例如键盘布局),或启用自动更正(如果键盘支持的话)。如果软件键盘不符合此处提供的选项,则无法保证某些选项的可用性。下面列出了支持的键盘选项

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

格式设置

TextField 允许您为输入值设置视觉格式,例如将密码中的字符替换为 *,或在信用卡号码中每 4 位插入一个连字符:

@Composable
fun PasswordTextField() {
    var password by rememberSaveable { mutableStateOf("") }

    TextField(
        value = password,
        onValueChange = { password = it },
        label = { Text("Enter password") },
        visualTransformation = PasswordVisualTransformation(),
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
    )
}

密码文字输入字段,其中文字被遮盖

如需查看更多示例,请参阅 VisualTransformSamples 源代码

参考链接:

  1. Compose Text 文本和 AnnotatedString 多种样式的文本详解
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值