阅读 255

初识 Jetpack Compose(六) :组件-Text fields

compose-landing-roadmap.svg

目录

一、TextFiled

fun TextField(
    // 文字,另外一个构造函数可传入TextFieldValue
    value: String, 
    // 内容变化回调监听
    onValueChange: (TextFieldValue) -> Unit, 
    // 修饰符
    modifier: Modifier = Modifier, 
    // 是否可用
    enabled: Boolean = true,
    // 是否只读
    readOnly: Boolean = false, 
    // 文字样式
    textStyle: TextStyle = LocalTextStyle.current, 
    // 标签(一个辅助提示文案)
    label: @Composable (() -> Unit)? = null,
    // 内容占位符,类似于hint,组件处于焦点时显示
    placeholder: @Composable (() -> Unit)? = null,
    // 头部图标
    leadingIcon: @Composable (() -> Unit)? = null, 
    // 尾部图标
    trailingIcon: @Composable (() -> Unit)? = null,
    // 指定当前输入文本是否出错,如果为错,则会把文字和线框显示为红色来提示
    isError: Boolean = false,
    // 输入值样式,比如显示密码(PasswordVisualTransformation())
    visualTransformation: VisualTransformation = VisualTransformation.None,
    // 定义软键盘上的返回键的功能,如 return/search 等
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    // 按下软键盘上 action 的回调
    keyboardActions: KeyboardActions = KeyboardActions(),
    // 是否单行显示
    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() 
)
复制代码

1.1. 管理状态

注意:Compose 编程思想中有讲到,当页面数据发生变化时,以前的 Android 布局一般需要使用 findViewById() 等函数遍历树,并通过调用诸如 setText(String) 等方法进行数据更改。这样会导致在项目在年月的更迭中维护和阅读成本逐渐变高,相信这一点很多小伙伴都深有体会。而Compose只会在页面数据发生变化时再去重绘。官方描述如下:

长期以来,Android 视图层次结构一直可以表示为界面微件树。由于应用的状态会因用户交互等因素而发生变化,因此界面层次结构需要进行更新以显示当前数据。最常见的界面更新方式是使用 findViewById() 等函数遍历树,并通过调用 button.setText(String)container.addChild(View) 或 img.setImageBitmap(Bitmap) 等方法更改节点。这些方法会改变微件的内部状态。 手动操纵视图会提高出错的可能性。如果一条数据在多个位置呈现,很容易忘记更新显示它的某个视图。此外,当两项更新以意外的方式发生冲突时,也很容易造成异常状态。例如,某项更新可能会尝试设置刚刚从界面中移除的节点的值。一般来说,软件维护复杂性会随着需要更新的视图数量而增长。 在过去的几年中,整个行业已开始转向声明性界面模型,该模型大大简化了与构建和更新界面关联的工程设计。该技术的工作原理是在概念上从头开始重新生成整个屏幕,然后仅执行必要的更改。此方法可避免手动更新有状态视图层次结构的复杂性。Compose 是一个声明性界面框架。 重新生成整个屏幕所面临的一个难题是,在时间、计算能力和电池用量方面可能成本高昂。为了减轻这一成本,Compose 会智能地选择在任何给定时间需要重新绘制界面的哪些部分。这会对您设计界面组件的方式有一定影响,如重组中所述。

所以,Compose不会每时每刻自动更新,而是必须明确获知新状态,才能相应地进行更新,所以!TextField 不会自行更新,但会在其 value 参数更改时更新。这就导致我们需要在TextFiled的输入监听中记录value改变的值,然后将这个值指向TextFiledvalue。比如:

//这样在软键盘输入值会触发 onValueChange 监听,但 TextField 的值不会改变
@Composable
fun inputPhone(){
    TextField(value = "", onValueChange = {})
}
复制代码

需要这样记录下监听到的值,然后再将值指向valueTextField得知value发生改变,则会去重绘UI。想更深入了解的小伙伴可以去看官方文档-管理状态一文。

@Composable
fun inputPhone(){
    var phone by rememberSaveable { mutableStateOf("") }

    TextField(value = phone, onValueChange = {
        phone = it
    })
}
复制代码

1.2. 使用示例

@Composable
fun inputPhone() {
    var phone by rememberSaveable { mutableStateOf("") }

    TextField(
        modifier = Modifier.background(Color.Cyan).fillMaxWidth(),
        value = phone,
        label = { Text(text = "Phone") },
        placeholder = { Text(text = "Input your phone number please.") },
        leadingIcon = {
            Icon(imageVector = Icons.Filled.Phone, contentDescription = null)
        },
        trailingIcon  = {
            Icon(imageVector = Icons.Filled.Clear, contentDescription = null,Modifier.clickable {
                //清空内容,改变phone的值就行
                phone = ""
            })
        },
        keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next,keyboardType = KeyboardType.Phone),
        singleLine = true,
        onValueChange = {
            phone = it
        })
}
复制代码

动画.gif

二、OutlinedTextField

OutlinedTextField 的构造参数与TextFiled完全一致,正如其名一样,它给输入框提供了外边框,所以OutlinedTextFieldTextFiled的区别仅为外观不一样。

三、BasicTextField

BasicTextField 更像是 xml 中的 EditText ,因为它没有其他的一些装饰,就是一个普通的输入框。其构可构造参数与 TextFiled 大致相同,下面列出独有的参数。

fun BasicTextField(
    ...
    //布局发生变化回调
    onTextLayout: (TextLayoutResult) -> Unit = {},
    // 画笔/画刷? 
    cursorBrush: Brush = SolidColor(Color.Black), 
    // 定义装饰框
    decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit = 
    @Composable { innerTextField -> innerTextField() }
)

复制代码

四、最后

好记性不如烂笔头,初识 Jetpack Compose 系列是我自己的学习笔记,在加深知识巩固的同时,也可以锻炼一下写作技能。文章中的内容仅作参考,如有问题请留言指正。

4.1. 参考

文章分类
Android