【自学Jetpack Compose 系列】Compose控件(二)Text与TextStyle的学习与使用

Android 的TextView在Compose中是使用的Text控件

文本显示

说到文本显示,我们打开之前创建的Compose项目,看到一下代码:

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
} 

看到的就是使用Text()进行文字显示。但是在Google官方建议我们使用字符串资源,方便我们以后进行国际化适配。那么我们要如何使用字符串资源呢?

@Composable
fun TestText(){
    Text(text = stringResource(id = R.string.app_name))
} 

在Compose中使用stringResource就可以直接读取字符串资源了。接下来我们就需要去预览效果了,之前我们有提到Preview注解,下面我们就使用它查看预览了:

@Preview(showBackground = true, heightDp = 100, widthDp = 200)
@Composable
fun TestTextPreview() {
    TestText()
} 

我看一下效果:

image.png 如果我们不需要进行其他设置的话,直接像上面那样使用Text即可,如果我们需要其他的设置,要如何实现一些文字效果?那么我们还是要去看一下源码:

@Composable
fun 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是必传的,其他参数都有默认值。

设置文字样式

1. 文字颜色

@Composable
fun TestText() {
    Text(
        text = stringResource(id = R.string.app_name),
        color = Color.Blue,
    )
} 

代码很简单, 我们只是把文字字体颜色设置为蓝色, 下面是预览效果:

image.png

2.字号大小

@Composable
fun TestText() {
    Text(
        text = stringResource(id = R.string.app_name),
        color = Color.Blue,
        fontSize = 25.sp
    )
} 

image.png 字号大小参数fontSize的类型是TextUnit。我们设置字号大小的时候使用了Int.sp的形式,其实这是Compose为我们写的扩展函数。Int、Float、Double都可以这样使用

@Stable
val Float.sp: TextUnit get() = pack(UNIT_TYPE_SP, this)

@Stable
val Double.sp: TextUnit get() = pack(UNIT_TYPE_SP, this.toFloat())

@Stable
val Int.sp: TextUnit get() = pack(UNIT_TYPE_SP, this.toFloat()) 

3. 设置斜体

@Composable
fun TestText() {
    Text(
        text = stringResource(id = R.string.app_name),
        color = Color.Blue,
        fontSize = 25.sp,
        fontStyle = FontStyle.Italic,
    )
} 

image.png 我们看一下FontStyle的源码:

inline class FontStyle(val value: Int) {

    override fun toString(): String {
        return when (this) {
            Normal -> "Normal"
            Italic -> "Italic"
            else -> "Invalid"
        }
    }

    companion object {
        /** Use the upright glyphs */
        val Normal = FontStyle(0)

        /** Use glyphs designed for slanting */
        val Italic = FontStyle(1)

        /** Returns a list of possible values of [FontStyle]. */
        fun values(): List<FontStyle> = listOf(Normal, Italic)
    }
} 

代码很简单,就是一个枚举类,只用两个参数:NormalItalic

4. 设置字体粗细

设置字体粗细用的是FontWeight,我们先看一下FontWeight的源码

@Immutable
class FontWeight(val weight: Int) : Comparable<FontWeight> {

    companion object {
        @Stable
        val W100 = FontWeight(100)
        @Stable
        val W200 = FontWeight(200)
        @Stable
        val W300 = FontWeight(300)
        @Stable
        val W400 = FontWeight(400)
        @Stable
        val W500 = FontWeight(500)
        @Stable
        val W600 = FontWeight(600)
        @Stable
        val W700 = FontWeight(700)
        @Stable
        val W800 = FontWeight(800)
        @Stable
        val W900 = FontWeight(900)
        @Stable
        val Thin = W100
        @Stable
        val ExtraLight = W200
        @Stable
        val Light = W300
        @Stable
        val Normal = W400
        @Stable
        val Medium = W500
        @Stable
        val SemiBold = W600
        @Stable
        val Bold = W700
        @Stable
        val ExtraBold = W800
        @Stable
        val Black = W900
        internal val values: List<FontWeight> = listOf(
            W100,
            W200,
            W300,
            W400,
            W500,
            W600,
            W700,
            W800,
            W900
        )
    }

    init {
        require(weight in 1..1000) {
            "Font weight can be in range [1, 1000]. Current value: $weight"
        }
    }
} 

代码内置了从W100 到 W900的粗细效果,根据实际情况使用哪种加粗。FontWeight有一个有参构造函数,方便我们自定义粗细程度。里面内置好的也有我们比较熟悉的BoldNormal

@Composable
fun TestText() {
    Text(
        text = stringResource(id = R.string.app_name),
        color = Color.Blue,
        fontSize = 25.sp,
        fontStyle = FontStyle.Italic,
        fontWeight = FontWeight.Bold
    )
} 

image.png

上面说了我们也可以自定义粗细的值:

@Composable
fun TestText() {
    Text(
        text = stringResource(id = R.string.app_name),
        color = Color.Blue,
        fontSize = 25.sp,
        fontStyle = FontStyle.Italic,
        fontWeight = FontWeight(10)
    )
} 

image.png 上面是我们把粗细值改成10的效果

5.设置字体

修改字体使用的是fontFamily参数,用于设置使用的字体。按照惯例,先看源码:

 sealed class FontFamily(val canLoadSynchronously: Boolean) {
    companion object {
        // 默认字体
        val Default: SystemFontFamily = DefaultFontFamily()
        // 具有低对比度和平淡笔画结尾的字体
        val SansSerif = GenericFontFamily("sans-serif")
        // Scripts 的正式文本
        val Serif = GenericFontFamily("serif")
        // 字形具有相同固定宽度的字体
        val Monospace = GenericFontFamily("monospace")
        // 草书、手写字体
        val Cursive = GenericFontFamily("cursive")
    }
} 

系统默认提供了5种字体,我们把这5种字体都使用一下看看效果:

@Composable
fun TestText() {
    Column {
        Text(text = stringResource(id = R.string.app_name), fontFamily = FontFamily.Default)
        Text(text = stringResource(id = R.string.app_name), fontFamily = FontFamily.SansSerif)
        Text(text = stringResource(id = R.string.app_name), fontFamily = FontFamily.Serif)
        Text(text = stringResource(id = R.string.app_name), fontFamily = FontFamily.Monospace)
        Text(text = stringResource(id = R.string.app_name), fontFamily = FontFamily.Cursive)
    }
} 

image.png

除了系统给的字体,我们还可以添加自定义字体和字型,首先我们要讲字体文件放到res/font文件夹中。

放置完字体后,需要根据字体文件来定义fontFamily:

val customFamily = FontFamily(
    Font(R.font.family_normal, FontWeight.Normal),
    Font(R.font.family_bold, FontWeight.Bold),
) 

然后,就可以将此fontFamily传递给Text来使用了:

Text(text = stringResource(id = R.string.app_name), fontFamily = customFamily, fontWeight = FontWeight.Bold) 

6. 设置字符间距

设置字符间距使用的是Text的letterSpacing参数。参数类型和设置字号大小是一样的:

@Composable
fun TestText() {
    Text(
        text = stringResource(id = R.string.app_name),
        letterSpacing = 5.sp
    )
} 

image.png

不是只有英文可是设置字符间距,中文也可以

image.png

7. 设置文字装饰

设置文字装饰用的是textDecoration参数,textDecoration我先去看一下这个源码:

@Immutable
class TextDecoration internal constructor(val mask: Int) {
    companion object {
        @Stable
        val None: TextDecoration = TextDecoration(0x0)
        // 下划线
        @Stable
        val Underline: TextDecoration = TextDecoration(0x1)
        // 删除线
        @Stable
        val LineThrough: TextDecoration = TextDecoration(0x2)
    }
} 

我们看看文字装饰怎么用?

@Composable
fun TestText() {
    Column {
        Text(
            text = "小码农沐枫",
            textDecoration = TextDecoration.None
        )
        Text(
            text = "小码农沐枫",
            textDecoration = TextDecoration.Underline
        )
        Text(
            text = "小码农沐枫",
            textDecoration = TextDecoration.LineThrough
        )
    }
} 

image.png

8. 文字对齐方式

设置文字的对齐方式使用的是textAlign参数。参数对应的类型是TextAlign, 先看一下源码:

inline class TextAlign internal constructor(internal val value: Int) {
    companion object {
        val Left = TextAlign(1)
        val Right = TextAlign(2)
        val Center = TextAlign(3)
        val Justify = TextAlign(4)
        val Start = TextAlign(5)
        val End = TextAlign(6)
    }
} 

我们以居中对齐为例:

Text(
    text = "小码农沐枫",
    textAlign = TextAlign.Center,
    modifier = Modifier.width(200.dp)
) 

image.png

9. 设置行高

设置行高使用的参数是lineHeight,参数类型也是TextUnit。

Text(
    text = "小码农沐枫小码农沐枫小码农沐枫",
    lineHeight = 35.sp
) 

image.png

10. 文字溢出

处理文字溢出的情况,使用的参数为overflow,参数类型为TextOverflow。直接看源码:

inline class TextOverflow internal constructor(internal val value: Int) {

    override fun toString(): String {
        return when (this) {
            Clip -> "Clip"
            Ellipsis -> "Ellipsis"
            Visible -> "Visible"
            else -> "Invalid"
        }
    }

    companion object {
       
        val Clip = TextOverflow(1)

        val Ellipsis = TextOverflow(2)

        val Visible = TextOverflow(3)
    }
} 

Text(
    text = "小码农沐枫小码农沐枫小码农沐枫",
    overflow = TextOverflow.Ellipsis,
    maxLines = 2
) 

image.png

11. 文字中富文本显示

这种在登录或注册页面的底部同意隐私权限的位置经常用到。

如果要实现这种效果,我们就需要借助AnnotatedString类来实现。先看源码:

@Immutable
class AnnotatedString internal constructor(
    val text: String,
    val spanStyles: List<Range<SpanStyle>> = emptyList(),
    val paragraphStyles: List<Range<ParagraphStyle>> = emptyList(),
    internal val annotations: List<Range<out Any>> = emptyList()
) 

  • text: 用于表示文字内容
  • spanStyles:用于在文本的特定部分指定SpanStyle
  • paragraphStyles:用于指定文字对齐、文字方向、行高和文字缩进样式。

TextStyle用于Text可组合项,而SpanStyle和ParagraphStyle用于AnnotatedString。

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

下面看看具体使用:

@Composable
fun TestText() {
    Text(buildAnnotatedString {
        withStyle(style = SpanStyle(color = Color.Gray, fontSize = 14.sp)){
            append("阅读并同意")
        }
        withStyle(style = SpanStyle(color = Color.Green, fontSize = 14.sp)){
            append("《用户协议》")
        }
        withStyle(style = SpanStyle(color = Color.Gray, fontSize = 14.sp)){
            append("和")
        }
        withStyle(style = SpanStyle(color = Color.Green, fontSize = 14.sp)){
            append("《隐私协议》")
        }
        withStyle(style = SpanStyle(color = Color.Gray, fontSize = 14.sp)){
            append("。")
        }
    })
} 

image.png

设置文字选择

在Compose中支持Text的精细互动,文字选择现在更加灵活,并且可以跨各种可组合项布局进行选择。
在默认情况下,可组合项不可选择,也就是说默认情况下用户无法选择和复制文字。要启用文字选择,需要使用SelectionContainer可组合项封装文字元素:

@Composable
fun TestText() {
    SelectionContainer(modifier = Modifier.fillMaxSize()) {
        Text(text = "我是可以选择的, 我是可以选择的, 我是可以选择的", fontSize = 35.sp)
    }
} 

这种需要长按的,我们预览就看不到效果了,我们只能去运行看效果:

image.png

比如说在一段文字中,我们有一部分是不想让用户去选中的,这个应该怎么做呢?在这里我们就可以借用DisableSelection可组合项来封装不可选择的部分:

@Composable
fun TestText() {
    SelectionContainer(modifier = Modifier.fillMaxSize()) {
        Column {
            Text(text = "鹅鹅鹅")
            Text(text = "曲项向天歌")
            DisableSelection {
                Text(text = "白毛浮绿水")
            }
            Text(text = "红掌拨清波")
        }
    }
} 

image.png
我们可以看到白毛浮绿水这句话就是不能选中的状态了

文末

我总结了一些Android核心知识点,以及一些最新的大厂面试题、知识脑图和视频资料解析。

需要的小伙伴直接点击文末小卡片免费领取哦,以后的路也希望我们能一起走下去。(谢谢大家一直以来的支持,需要的自己领取)

Android学习PDF+架构视频+面试文档+源码笔记

部分资料一览:

  • 330页PDF Android学习核心笔记(内含8大板块)

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

  • Android BAT大厂面试题(有解析)

领取地址:

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值