Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > Jetpack Compose文字组件

Jetpack Compose基础组件之文字组件

作者:时光剑客

这篇文章主要为大家介绍了Jetpack Compose基础组件之文字组件使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

概述

文本是UI界面中最常见的元素之一,在Compose中,文字组件扮演着重要的角色,文字组件是遵循Material Design规范设计的上层组件,如果我们不想使用Material Design,我们也可以直接使用更底层的文本组件,如Text组件对应的更底层的文本组件是BasicText,文本组件不得不提输入框的使用,本文会主要介绍Text和输入框,并且实现一个现在App中都在用的好看的输入框

文字组件

1.Text 文本

因为Composable组件都是函数,所有的配置都来自于参数的传递,所以我们通过参数列表就可以了解组件的所有功能,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,// 控制文本是否能够换行,如果为false,则会定位
    maxLines: Int = Int.MAX_VALUE,// 文本最多的展示行数
    onTextLayout: (TextLayoutResult) -> Unit = {},// 在文本发生变化之后,会回调一个TextLayoutResult,包含此文本的各种信息
    style: TextStyle = LocalTextStyle.current // 文本的风格配置,如颜色,字体,行高等
)

Text组件的参数会按照其使用的频度排序,比如text和modifier排在靠前的位置,并尽量添加默认实现。

Text组件的基本功能是显示一段文字,可以为text参数传入要显示的文字内容,Compose也提供了stringResource方法,通过R 资源文件获取字符串,方便做多语言适配

        // 指定字符串
        Text(text = "Hello World")
        // 指定文字资源
        Text(text = stringResource(id = R.string.app_name))

2.Text的style文字样式

style参数接受一个TextStyle类型,TextStyle中包含了一系列设置文字样式的字段,例如行高,间距,字体大小,字体粗细等,演示代码如下所示:

@Composable
fun TextStyleDemo() {
    Column {
        Text(
            text = "Zhongxj",
            style = TextStyle(
                fontSize = 25.sp,
                fontWeight = FontWeight.Bold,
                background = Color.Cyan,
                lineHeight = 35.sp
            )
        )
        Text(
            text = stringResource(id = R.string.app_name), style = TextStyle(
                color = Color.Cyan,
                letterSpacing = 4.sp
            )
        )
        Text(
            text = "Hello world", style = TextStyle(
                textDecoration = TextDecoration.LineThrough
            )
        )
        Text(
            text = "Walt-zhong",
            style = MaterialTheme.typography.h6.copy(fontStyle = FontStyle.Italic)
        )
    }
}

运行结果如下所示:

代码中的TextDecoration可以为文字增加删除线或下划线,FontStyle可以用来设置文字是否是斜体

3.maxLines参数

maxLines参数可以帮助我们将文本限制在指定行数之间,当文本超过了参数设置的阈值时,文本会被截断,而overflow可以处理文字过多的场景,文字过多的时候会以“...”结尾,这个参数可以用来实现一个阅读文字时的展开和收起功能,当我们显示很多条数据时,每一条数据都有很多的文字,这时我们可以使用这个参数,默认只展示指定的行数,提供一个展开按钮,当用户点击展开的时候,就显示所有的文本。展示收起按钮,点击收起按钮又可以显示指定的行数。这个功能后面有时间我们会演示,这里我们先看下基本的演示代码:

@Composable
fun MaxLinesDemo() {
    Column {
        Text(
            text = "在Compose中,每一个组件都是带有@Compose注解的函数,被称为Composable。" +
                    "Compose已经预置了很多的Compose UI组件,这些组件都是基于Material Design规范设计的",
            style = MaterialTheme.typography.body1,
            color = Color.Red
        )
        Spacer(modifier = Modifier.size(10.dp))
        Text(
            text = "在Compose中,每一个组件都是带有@Compose注解的函数,被称为Composable。" +
                    "Compose已经预置了很多的Compose UI组件,这些组件都是基于Material Design规范设计的",
            style = MaterialTheme.typography.body1,
            maxLines = 1,
            color = Color.Green
        )
        Spacer(modifier = Modifier.size(10.dp))
        Text(
            text = "在Compose中,每一个组件都是带有@Compose注解的函数,被称为Composable。" +
                    "Compose已经预置了很多的Compose UI组件,这些组件都是基于Material Design规范设计的",
            style = MaterialTheme.typography.body1,
            maxLines = 1,
            color = Color.Blue,
            overflow = TextOverflow.Ellipsis
        )
    }
}

运行结果:

4.fontFamily字体风格

fontFamily参数用来设置文字字体,演示代码如下:

@Composable
fun FontFamilyDemo() {
    Column {
        Text(text = "Hello World", color = Color.Red)
        Spacer(modifier = Modifier.size(10.dp))
        Text(text = "Hello World", color = Color.Green, fontFamily = FontFamily.Monospace)
        Spacer(modifier = Modifier.size(10.dp))
        Text(text = "Hello World", color = Color.Blue, fontFamily = FontFamily.Cursive)
    }
}

运行结果

当使用系统中没有的字体时,可以右击res文件夹,选择New->Android Resource Directory->Resource type ->font创建font文件夹,然后将自己的字体拖入文件夹即可

5.AnnotatedString多样式文字

AnnotatedString 其实很像传统View中的SpannableString,在很多的场景中,我们需要在一段文字中突出某些内容,比如超链接和电话号码,我们点击超链接和电话号码能跳到链接指向的页面和拨打电话。在Compose中就需要使用AnnotatedString多样式文字,AnnotatedString是一个数据类,除了文本值,它还包含了一个SpanStyle和ParagraphStyle的Range列表,SpanStyle用于描述在文本中字串的文字样式,ParagraphStyle则用于描述文本字串中的段落样式,Range确定字串的范围,示例代码如下:

@Composable
fun AnnotatedStringDemo() {
    Text(text = buildAnnotatedString {
        withStyle(style = SpanStyle(fontSize = 24.sp)) {
            append("I am Iron man,我是钢铁侠")
        }
        withStyle(style = SpanStyle(fontWeight = FontWeight.W900, fontSize = 24.sp)) {
            append("zhongxj")
        }
        append("\n")
        withStyle(style = ParagraphStyle(lineHeight = 25.sp)) {
            append(
                "在Compose中,每一个组件都是带有@Compose注解的函数,被称为Composable。" +
                        "Compose已经预置了很多的Compose UI组件,这些组件都是基于Material Design规范设计的"
            )
        }
        append("\n")
        append("Now,We are working hard")
        append(annotatedText)
    })
}

运行结果如下:

SpanStyle继承了TextStyle中关于文字样式相关的字段,而ParagraphyStyle继承了TextStyle中控制锻炼的样式,例如textAlign,lineHeight等。SpanStyle和ParagraphyStyle中的设置优先于整个TextStyle中同名属性的设置

看到上图中的绿色文字,是不是有一种想点击的冲动,可惜现在是无法点击的,若要实现点击,我们需要借助于ClickedText.演示代码如下:

@Composable
fun ClickTextDemo() {
    ClickableText(text = annotatedText, onClick = { offset ->
        annotatedText.getStringAnnotations(
            tag = "URL",
            start = offset,
            end = offset
        ).firstOrNull()?.let {
            Log.d("zhongxj", "click me, content: $it")
        }
    })
}
val annotatedText = buildAnnotatedString {
    withStyle(style = ParagraphStyle(lineHeight = 25.sp)) {
        append(
            "在Compose中,每一个组件都是带有@Compose注解的函数,被称为Composable。" +
                    "Compose已经预置了很多的Compose UI组件,这些组件都是基于Material Design规范设计的"
        )
    }
    append("\n")
    pushStringAnnotation(tag = "URL", annotation = "http://xxxxx")
    withStyle(
        style = SpanStyle(
            fontWeight = FontWeight.W900,
            textDecoration = TextDecoration.Underline,
            color = Color(0xFF59A869)
        )
    ) {
        append("点击我,了解更多")
    }
}

运行结果如下:

这样才可以点击,点击的时候我们打了一个Log,证明点击生效了

6.SelectionContainer可选中文字

Text自身默认是不能被长按选择的,否则在Button使用的时候,就会出现传统View的Button是可粘贴的Button的按钮,Compose提供了专门的SelectionContainer组件对包裹的Text进行选中,演示代码如下:

@Composable
fun SelectionContainerDemo() {
    SelectionContainer {
        Text(text = "我是可以被复制的文字")
    }
}

运行结果:

7.TextField输入框

TextField组件是我们最常用的文本输入框,遵循Material Design设计准则,它有一个低级别的底层组件,BasicTextField.TextField有两种风格,默认的(filled)和OutlinedTextField我们可以先看下输入框的参数

@Composable
fun TextField(
    value: String, // 输入框显示的文本
    onValueChange: (String) -> Unit, // 当输入框内的文字发生改变时的回调,其中带有最新的文本参数
    modifier: Modifier = Modifier,// 修饰符
    enabled: Boolean = true,// 是否启用
    readOnly: Boolean = false, // 控制输入框的可编辑状态
    textStyle: TextStyle = LocalTextStyle.current, // 输入框内文字样式
    label: @Composable (() -> Unit)? = null, // 可选的标签,将显示在输入框内
    placeholder: @Composable (() -> Unit)? = null, // 占位符,当输入框处于焦点位置且输入框文本为空时显示
    leadingIcon: @Composable (() -> Unit)? = null, // 输入框开头的前置图标
    trailingIcon: @Composable (() -> Unit)? = null,// 输入框末尾的后置图标
    isError: Boolean = false, // 指示输入框当前值是否有错,当值为true时,标签底部指示器和尾部图标将以错误的颜色显示
    visualTransformation: VisualTransformation = VisualTransformation.None,// 输入框内的文字视觉
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default, // 软键盘选项,包含键盘类型和ImeAction等配置
    keyboardActions: KeyboardActions = KeyboardActions(), // 当输入服务发出一个IME动作时,相应的回调被调用
    singleLine: Boolean = false,// 输入框是否只能输入一行
    maxLines: Int = Int.MAX_VALUE, // 输入框能输入的最大行数
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, // 监听组件的状态便于自定义
    // 组件不同状态下的样式
    shape: Shape =
        MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),// 输入框的外观形状
    colors: TextFieldColors = TextFieldDefaults.textFieldColors() // 输入框的颜色组
) 

演示示例如下所示:

@Composable
fun TextFieldDemo() {
    var text by remember {
        mutableStateOf("")
    }
    TextField(value = text, onValueChange = {
        text = it
    },
        label = { Text(text = "用户名") })
}

运行结果

输入框附带一个label,label会更具输入框获得焦点而呈现出不同的效果,底部会有一个高亮的图标,代码中有关于State的使用,此处不做讲解,这里用于展示使用

我们还可以给输入框添加装饰,代码如下:

@Composable
fun TextFieldWithDec() {
    var username by remember {
        mutableStateOf("")
    }
    var password by remember {
        mutableStateOf("")
    }
    Column {
        TextField(value = username, onValueChange = {
            username = it
        }, label = { Text(text = "用户名") }, leadingIcon = {
            Icon(imageVector = Icons.Filled.AccountBox, contentDescription = "用户名")
        })
        TextField(value = password, onValueChange = {
            password = it
        }, label = { Text(text = "密码") }, trailingIcon = {
            IconButton(onClick = { /*TODO*/ }) {
                Icon(
                    painter = painterResource(id = R.drawable.password),
                    modifier = Modifier.size(16.dp),
                    contentDescription = "password"
                )
            }
        })
    }
}

运行结果

8.OutlinedTextField边框样式输入框

OutlinedTextField是按照Material Design规范设计的另一种风格的输入框,除了外观上带有一个边框,其他用法和TextField基本一致,演示代码如下:

@Composable
fun OutlineTextFieldDemo()
{
    var text by remember {
        mutableStateOf("")
    }
    OutlinedTextField(value = text, onValueChange = {text = it},
        label = { Text(text = "用户名")})
}

运行结果:

9.BasicTextField

BasicTextField是一个更低级别的Compose组件,与TextField,OutlinedTextField不同的是,BasicTextField拥有更多的自定义效果,我们可以看下BasicTextField为我们提供的可选参数列表:

@Composable
fun BasicTextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = TextStyle.Default,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = false,
    maxLines: Int = Int.MAX_VALUE,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    onTextLayout: (TextLayoutResult) -> Unit = {}, // 当输入框文本更新时的回调包括当前文本的各种信息
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    cursorBrush: Brush = SolidColor(Color.Black), // 输入框光标的颜色
    decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
        @Composable { innerTextField -> innerTextField() } // 允许在TextField周围添加修饰的Composable lambda,需要在布局中
        // 中调用innerTextField()才能完成TextField的创建
)

我们可以看到,BasicTextField的参数和TextField的参数有很多共同的地方,我们自定义的关键在于最后一个参数decorationBox,decorationBox是一个Composable,它回调了一个innerTextField函数给我们,innerTextField是框架定义好给我们使用的,它就是文字输入的入口,所以需要创建一个完整的输入框界面,并且在合适的地方调用这个函数,我们实现一个仿当前大多是app都会使用的输入框结束今天的内容:代码如下

@Composable
fun SearchBar() {
    var text by remember {
        mutableStateOf("")
    }
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color(0xFFD3D3D3)),
        contentAlignment = Alignment.Center
    )
    {
        BasicTextField(value = text, onValueChange = {
            text = it
        }, decorationBox = { innerTextField ->
            Row(
                verticalAlignment = Alignment.CenterVertically,
                modifier = Modifier.padding(vertical = 2.dp, horizontal = 8.dp)
            ) {
                Icon(imageVector = Icons.Filled.Search, contentDescription = null)
                Box(
                    modifier = Modifier.padding(horizontal = 10.dp),
                    contentAlignment = Alignment.CenterStart
                ) {
                    if (text.isEmpty()) {
                        Text(
                            text = "请输入", style = TextStyle(
                                color = Color(0, 0, 0, 128)
                            )
                        )
                    }
                    innerTextField()
                }
                Box(
                    modifier = Modifier.fillMaxWidth(),
                    contentAlignment = Alignment.CenterEnd
                ) {
                    if (text.isNotEmpty()) {
                        IconButton(onClick = { text = "" }, modifier = Modifier.size(16.dp)) {
                            Icon(
                                imageVector = Icons.Filled.Close, contentDescription = null
                            )
                        }
                    }
                }
            }
        }, modifier = Modifier
            .padding(horizontal = 10.dp)
            .background(Color.White, CircleShape)
            .height(30.dp)
            .fillMaxWidth()
        )
    }
}

运行结果

总结

至此,我们的文字组件就介绍完了,本文只是简单的介绍了文字组件的入门功能,如果读者想要实现更加复杂绚丽的功能,请查看官方文档和脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文