Jetpack Composes 学习【02】Text
- 2022 年 6 月 06 日
本文字数:10116 字
阅读完需:约 33 分钟
Text
@Composablefun Text( text: String, modifier: Modifier = Modifier, color: Color = Color.Unspecified, 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, onTextLayout: (TextLayoutResult) -> Unit = {}, style: TextStyle = LocalTextStyle.current)Text 是 Compose 中最基本的布局组件,它可以显示文字
@Composablefun TextDemo() { Text("Hello World")}从 res 中加载文字
@Composablefun TextDemo() { Text(stringResource(id = R.string.content))}<resources> <string name="app_name">composestudy</string> <string name="content">秋刀鱼不会过期</string></resources>1. style 参数
style 参数可以帮助我们配置文本的行高,颜色,粗体等设置
package com.example.composestudyimport android.os.Bundleimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.compose.foundation.layout.Columnimport androidx.compose.material.MaterialThemeimport androidx.compose.material.Textimport androidx.compose.runtime.Composableimport androidx.compose.ui.tooling.preview.Previewclass MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {TextDemo()}}}@Composablefun TextDemo() {Column{Text(text = "这是一个标题",style = MaterialTheme.typography.h6)Text(text ="我是内容",style = MaterialTheme.typography.body2)}}@Preview(name = "Light Mode")@Composablefun PreviewMessageCard() {TextDemo()}
文字间距
package com.example.composestudyimport android.os.Bundleimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.compose.foundation.layout.Columnimport androidx.compose.foundation.layout.fillMaxWidthimport androidx.compose.material.MaterialThemeimport androidx.compose.material.Textimport androidx.compose.runtime.Composableimport androidx.compose.ui.Alignmentimport androidx.compose.ui.Modifierimport androidx.compose.ui.text.TextStyleimport androidx.compose.ui.text.font.FontWeightimport androidx.compose.ui.tooling.preview.Previewimport androidx.compose.ui.unit.spclass MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { TextDemo() } }}@Composablefun TextDemo() { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = "大前端之旅", style = TextStyle( fontWeight = FontWeight.W900, //设置字体粗细 fontSize = 20.sp, letterSpacing = 7.sp ) ) }}@Preview(name = "Light Mode")@Composablefun PreviewMessageCard() { TextDemo()}
2. maxLines 参数
使用 maxLines 参数可以帮助我们将文本限制在指定的行数之间,如果文本足够短则不会生效,如果文本超过 maxLines 所规定的行数,则会进行截断
@Composablefun TextDemo() { Column{ Text( text = "男人最好的状态是,25岁的时候能带着30岁的成熟去经营爱情,30岁的时候还带着18岁的不怕,去勇敢爱💪", style = MaterialTheme.typography.h6, maxLines = 1, ) Text( text ="大前端之旅", style = MaterialTheme.typography.body2 ) }}overflow 处理溢出
使用 overflow 参数可以帮助我们处理溢出的视觉效果
@Composablefun TextDemo() { Column{ Text( text = "男人最好的状态是,25岁的时候能带着30岁的成熟去经营爱情,30岁的时候还带着18岁的不怕,去勇敢爱💪", style = MaterialTheme.typography.h6, maxLines = 1, overflow = TextOverflow.Ellipsis ) Text( text ="大前端之旅", style = MaterialTheme.typography.body2 ) }}
3. textAlign 参数
当我们在 Text 中设置了 fillMaxWidth() 之后,我们可以指定 Text 的对齐方式
@Composablefun TextDemo() { Column { Text( text = "每天摸鱼", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Left ) Text( text = "这好吗", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center ) Text( text = "这非常的好", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Right ) }}
注意
需要注意区分的是,TextAlign 设置的是文本的对齐方式,而不是位置方向
如果需要实现 Text 组件居中,或者水平位置中其他方向,请参考这里
4. lineHeight 参数
使用 lineHeight 参数可以让我们指定 Text 中每行的行高间距
Column { Text( text = "大前端之旅".repeat(15), ) Spacer(Modifier.padding(vertical = 15.dp)) Text( text = "大前端之旅".repeat(15), lineHeight = 30.sp )}
5. fontFamily 参数
使用 fontFamily 参数可以让我们自定义字体,它的调用方法是这样的:
Column { Text("Hello World", fontFamily = FontFamily.Serif) Text("Hello World", fontFamily = FontFamily.SansSerif)}
你也可以加载 res/font 下的字体。
创建一个 font 文件夹可以右键 res 文件夹,选择 Android Resource Directory -> 选择 font
Text( text = "男人最好的状态是,25岁的时候能带着30岁的成熟去经营爱情,30岁的时候还带着18岁的不怕,去勇敢爱💪", fontFamily = FontFamily( Font(R.font.pingfang, FontWeight.W700) ))6. 可点击的 Text
有的时候也许您需要将文本当作按钮,那么只需要添加 Modifier.clickable 即可
代码如下:
@Composablefun TextDemo() { Text( text = "确认编辑", modifier = Modifier.clickable( onClick = { // TODO }, ) )}取消点击波纹
但是我们会发现,clickable 有自带的波纹效果,如果我们想要取消的话,只需要添加两个参数即可:
@Composablefun TextDemo() { // 获取 context val context = LocalContext.current Text( text = "确认编辑", modifier = Modifier.clickable( onClick = { // 通知事件 Toast.makeText(context, "你点击了此文本", Toast.LENGTH_LONG).show() }, indication = null, interactionSource = MutableInteractionSource() ) )}效果如下:
7. 特定的文字显示
如果我们想让一个 Text 语句中使用不同的样式,比如粗体提醒,特殊颜色
则我们需要使用到 AnnotatedString
AnnotatedString 是一个数据类,其中包含了:
一个
Text的值一个
SpanStyleRange的List,等同于位置范围在文字值内的内嵌样式一个
ParagraphStyleRange的List,用于指定文字对齐、文字方向、行高和文字缩进样式
inline fun <R : Any> AnnotatedString.Builder.withStyle( style: SpanStyle, block: AnnotatedString.Builder.() -> crossinline R): R一个简单的代码演示:
@Composablefun TextDemo() { Column( modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { Text( buildAnnotatedString { append("你现在观看的章节是 ") withStyle(style = SpanStyle(fontWeight = FontWeight.W900)) { append("Text") } } ) }}效果如下:
8. 文字超链接?(ClickableText)
在第 6 部分我们已经介绍了可以通过 AnnotatedString 来完成在一个 Text 中给不同的文字应用不同的样式
在第 5 部分我们已经介绍了可以通过 Modifier.Clickable() 来完成检测 Text 的点击
但是 Modifier.Clickable() 无法检测 Text 中的部分点击,那如果我们需要检测一个 Text 中的部分点击事件该怎么办呢?就像我们经常在 App 底下看到的用户协议等
其实很简单,Compose 也给我们准备了 ClickableText,来看看如何使用吧!
package com.example.composestudyimport android.content.ContentValues.TAGimport android.os.Bundleimport android.util.Logimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.compose.foundation.layout.Columnimport androidx.compose.foundation.layout.Spacerimport androidx.compose.foundation.layout.fillMaxWidthimport androidx.compose.foundation.layout.paddingimport androidx.compose.foundation.text.ClickableTextimport androidx.compose.material.MaterialThemeimport androidx.compose.material.Textimport androidx.compose.runtime.Composableimport androidx.compose.ui.Alignmentimport androidx.compose.ui.Modifierimport androidx.compose.ui.graphics.Colorimport androidx.compose.ui.text.SpanStyleimport androidx.compose.ui.text.TextStyleimport androidx.compose.ui.text.buildAnnotatedStringimport androidx.compose.ui.text.font.FontWeightimport androidx.compose.ui.text.style.TextOverflowimport androidx.compose.ui.text.withStyleimport androidx.compose.ui.tooling.preview.Previewimport androidx.compose.ui.unit.dpimport androidx.compose.ui.unit.spclass MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { TextDemo() } }}@Composablefun TextDemo() { val text = buildAnnotatedString { append("勾选即代表同意") withStyle( style = SpanStyle( color = Color(0xFF0E9FF2), fontWeight = FontWeight.Bold ) ) { append("用户协议") } } ClickableText( text = text, onClick = { offset -> Log.d(TAG, "Hi,你按到了第 $offset 位的文字") } )}@Preview(name = "Light Mode")@Composablefun PreviewMessageCard() { TextDemo()}
但是...怎么才能检测用户协议这四个字符的点击事件呢?
也不用怕,Compose 还在 buildAnnotatedString 和 ClickableText 中引入了相应的方法
先来看看代码吧!
val annotatedText = buildAnnotatedString { append("勾选即代表同意") pushStringAnnotation( tag = "tag", annotation = "一个用户协议啦啦啦,内容内容" ) withStyle( style = SpanStyle( color = Color(0xFF0E9FF2), fontWeight = FontWeight.Bold ) ) { append("用户协议") } pop()}ClickableText( text = annotatedText, onClick = { offset -> annotatedText.getStringAnnotations( tag = "tag", start = offset, end = offset ).firstOrNull()?.let { annotation -> Log.d(TAG, "你已经点到 ${annotation.item} 啦") } })
在上面的代码中
多了一个
pushStringAnnotation()方法,它会将给定的注释附加到任何附加的文本上,直到相应的pop被调用getStringAnnotations()方法是查询附加在这个AnnotatedString上的字符串注释。注释是附加在AnnotatedString上的元数据,例如,在我们的代码中"tag"是附加在某个范围上的字符串元数据。注释也与样式一起存储在Range中
小试牛刀
那么,你已经学会了如何自定义 Text 中的样式和点击事件,来尝试做出一个这样的效果?
实现的代码可以通过以下的方式来查看
package com.example.composestudyimport android.content.ContentValues.TAGimport android.os.Bundleimport android.util.Logimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.compose.foundation.layout.*import androidx.compose.foundation.text.ClickableTextimport androidx.compose.material.AlertDialogimport androidx.compose.material.Buttonimport androidx.compose.material.MaterialThemeimport androidx.compose.material.Textimport androidx.compose.runtime.*import androidx.compose.ui.Alignmentimport androidx.compose.ui.Modifierimport androidx.compose.ui.graphics.Colorimport androidx.compose.ui.res.stringResourceimport androidx.compose.ui.semantics.Role.Companion.Buttonimport androidx.compose.ui.text.SpanStyleimport androidx.compose.ui.text.TextStyleimport androidx.compose.ui.text.buildAnnotatedStringimport androidx.compose.ui.text.font.FontWeightimport androidx.compose.ui.text.style.TextOverflowimport androidx.compose.ui.text.withStyleimport androidx.compose.ui.tooling.preview.Previewimport androidx.compose.ui.unit.dpimport androidx.compose.ui.unit.spclass MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {TextDemo()}}}@Composablefun TextDemo() {var content by remember{ mutableStateOf("")}val openDialog = remember { mutableStateOf(false) }val annotatedText = buildAnnotatedString {append("勾选即代表同意")pushStringAnnotation(tag = "tag",annotation = stringResource(id = R.string.content))withStyle(style = SpanStyle(color = Color(0xFF0E9FF2),fontWeight = FontWeight.Bold)) {append("用户协议")}pop()}Box(modifier = Modifier.fillMaxSize().padding(bottom = 15.dp),contentAlignment = Alignment.BottomCenter){ClickableText(text = annotatedText,onClick = { offset ->annotatedText.getStringAnnotations(tag = "tag", start = offset,end = offset).firstOrNull()?.let { annotation ->openDialog.value = truecontent = annotation.item}})}if(openDialog.value){AlertDialog(onDismissRequest = {openDialog.value = false},title = {Box(Modifier.fillMaxWidth(),contentAlignment = Alignment.Center){Text(text = "用户协议",style = MaterialTheme.typography.h6,)}},text = {Text(content)},confirmButton = {Button(onClick = {openDialog.value = false}){Text("确认")}},dismissButton = {Button(onClick = {openDialog.value = false}){Text("取消")}})}}@Preview(name = "Light Mode")@Composablefun PreviewMessageCard() {TextDemo()}
9. 文字复制
默认情况下 Text 并不能进行复制等操作,我们需要设置 SelectionContainer 来包装 Text
package com.example.composestudyimport android.os.Bundleimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.compose.foundation.layout.Columnimport androidx.compose.foundation.layout.fillMaxWidthimport androidx.compose.foundation.text.selection.SelectionContainerimport androidx.compose.material.Textimport androidx.compose.runtime.Composableimport androidx.compose.ui.Modifierimport androidx.compose.ui.text.style.TextAlignimport androidx.compose.ui.tooling.preview.Previewclass MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { TextDemo() } }}@Composablefun TextDemo() { SelectionContainer { Column{ Text( text = "每天摸鱼", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Left ) Text( text = "这好吗", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center ) Text( text = "这非常的好", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Right ) } }}@Preview(name = "Light Mode")@Composablefun PreviewMessageCard() { TextDemo()}
10. 文字强调效果
文字根据不同情况来确定文字的强调程度,以突出重点并体现出视觉上的层次感。
Material Design 建议采用不同的不透明度来传达这些不同的重要程度,你可以通过 LocalContentAlpha 实现此功能。
您可以通过为此 CompositionLocal 提供一个值来为层次结构指定内容 Alpha 值。(CompositionLocal 是一个用于隐式的传递参数的组件,后续会提到)
package com.example.composestudyimport android.os.Bundleimport androidx.activity.ComponentActivityimport androidx.activity.compose.setContentimport androidx.compose.foundation.layout.Columnimport androidx.compose.material.ContentAlphaimport androidx.compose.material.LocalContentAlphaimport androidx.compose.material.Textimport androidx.compose.runtime.Composableimport androidx.compose.runtime.CompositionLocalProviderimport androidx.compose.ui.tooling.preview.Previewclass MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { TextDemo() } }}@Composablefun TextDemo() { Column() { // 将内部 Text 组件的 alpha 强调程度设置为高// 注意: MaterialTheme 已经默认将强调程度设置为 high CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) { Text("这里是high强调效果") }// 将内部 Text 组件的 alpha 强调程度设置为中 CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text("这里是medium强调效果") }// 将内部 Text 组件的 alpha 强调程度设置为禁用 CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Text("这里是禁用后的效果") } }}@Preview(name = "Light Mode")@Composablefun PreviewMessageCard() { TextDemo()}这是运行效果:
这张图可以很好的说明这个效果
11. 文字水平位置
一般情况下,Text 不会水平居中,如果你在 Row, Column, Box 这些 Composable 里面想要实现居中的效果,你可以在 Text 外围写一个 Box, Row, Column 等
像这样:
Column { Text("123") Text("456") Box( modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center ) { Text("789") }}
水平靠左: Alignment.Start
水平靠右: Alignment.End
如果你的 Column 有 Modifier.fillMaxWidth() 的属性或者指定了宽度/大小,那么你可以直接在 Text 里面写 Modifier.align(Alignment.CenterHorizontally) 来让 Text 处于水平居中的位置
12. 更多
版权声明: 本文为 InfoQ 作者【坚果】的原创文章。
原文链接:【http://xie.infoq.cn/article/e82d59473ecf57b345bd0dd8e】。文章转载请联系作者。
坚果
此间若无火炬,我便是唯一的光 2020.10.25 加入
公众号:“大前端之旅”,华为云享专家,InfoQ签约作者,51CTO博客首席体验官,专注于大前端技术的分享,包括Flutter,小程序,安卓,VUE,JavaScript。










评论