【自学Jetpack Compose 系列】Compose控件(三)修饰符---Modifier、输入框---TextFie的学习与使用

339 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天 点击查看活动详情

一、修饰符---Modifier

前面我们给Text设置宽高的时候,有用到一个Modifier,我们称为修饰符。Google官方对Modifier的描述为:一个有序的、不可变的修饰元素集合,用于给Compose UI元素添加装饰或者行为,例如背景、内边距、点击事件等,或者给Text设置单行、给Button设置各种点击状态等行为。

1. 内边距 padding

如何为控件添加内边距:

Text(text = "小码农沐枫", modifier = Modifier.padding(30.dp))

很简单,只需要调用padding并传入相应的dp就行了。那我们看一看padding的源码是怎样的吧:

@Stable
fun Modifier.padding(
    start: Dp = 0.dp,
    top: Dp = 0.dp,
    end: Dp = 0.dp,
    bottom: Dp = 0.dp
)

@Stable
fun Modifier.padding(
    horizontal: Dp = 0.dp,
    vertical: Dp = 0.dp
)

@Stable
fun Modifier.padding(all: Dp)

我们可以看到,padding有多种设置方式,可以单独设置一边,也可以统一设置上下的或左右的,还可以设置所有的。

2. 设置控件的尺寸

在以前我们布局的时候,一般有三种设置布局大小的方法:充满父布局、自适应大小和固定大小。这三种情况放在Compose中又该如何实现呢?

1. 充满父布局

Text(text = "小码农沐枫", modifier = Modifier.fillMaxSize())

是不是很简单,但是如果我们只需要充满高或者宽呢?

Text(text = "小码农沐枫", modifier = Modifier.fillMaxHeight())
Text(text = "小码农沐枫", modifier = Modifier.fillMaxWidth())

2. 自适应大小

这种又该如何实现呢?其实更简单,就是我们什么都不加,它就是自适应大小的

3. 固定大小

如何设置固定大小的呢?这有两种写法,一种是宽高一样的情况下,一种是分别设置宽高的情况

Text(text = "小码农沐枫", modifier = Modifier.size(100.dp))
Text(text = "小码农沐枫", modifier = Modifier.size(width = 100.dp, height = 50.dp))

3. weight修饰符

说起weight,相比大家都非常熟悉了,在XML布局中,在线性布局中进行设置权重。在Compose中也是直接使用weight来设置权重。

Row(
    Modifier
        .fillMaxSize()
        .padding(top = 20.dp)) {
    Box(modifier = Modifier
        .weight(1f)
        .height(50.dp).background(Color.Red))
    Box(modifier = Modifier
        .weight(2f)
        .height(50.dp).background(Color.Green))
}

我们来看一下运行效果:

image.png

4. 给控件添加点击事件

在Compose中,Modifier就可以设置点击事件:

Text(text = "小码农沐枫", modifier = Modifier.clickable {
    // 执行点击操作
})

5. 给控件添加圆角

在Compose中想要为控件设置圆角的话,通过Modifier.shadow就可以实现,话不多说,先看源码:

@Stable
fun Modifier.shadow(
    elevation: Dp,// 阴影的高度
    shape: Shape = RectangleShape,// Shape
    clip: Boolean = elevation > 0.dp// 是否将内容图形剪裁到该形状
)
@Composable
fun TestText() {
    MyComposeDemoTheme{
        Image(
            painter = painterResource(id = R.drawable.ic_launcher_background),
            contentDescription = "",
            modifier = Modifier
                .size(50.dp)
                .shadow(elevation = 4.dp, shape = MaterialTheme.shapes.medium)
        )
    }

}

@Preview(showBackground = true)
@Composable
fun TestTextPreview() {
    TestText()
}

看一下效果:

image.png

Compose中的EditText

在上一篇说到了Compose中的TextView --- Text,在这里我们一起去学习Compose中的EditText --- TextField。

1. 文本的输入和修改

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

1.TextField

先看看它是如何使用的?

@Composable
fun TestText() {
    val text = remember {
        mutableStateOf("你好, 沐枫")
    }
    Box(modifier = Modifier.size(width = 200.dp, height = 50.dp)){
        TextField(
            value = text.value,
            onValueChange = { text.value = it },
            label = { Text(text = "Label") },
        )
    }
}

看一下运行效果:

image.png

我们在看一下OutlinedTextField的使用:

@Composable
fun TestText() {
    val text = remember {
        mutableStateOf("你好, 沐枫")
    }
    Box(modifier = Modifier.size(width = 200.dp, height = 50.dp)){
        OutlinedTextField(
            value = text.value,
            onValueChange = { text.value = it },
            label = { Text(text = "Label") },
        )
    }

}

用法和TextField一样, 下面我们看一下运行效果:

image.png

2.BasicTextField

BasicTextField允许用户通过硬件键盘或软件键盘编辑文字,但是没有提供提示或占位符等装饰。用法如下:

@Composable
fun TestText() {
    val text = remember {
        mutableStateOf("你好, 沐枫")
    }
    Box(modifier = Modifier.size(width = 200.dp, height = 50.dp)){
        BasicTextField(
            value = text.value,
            onValueChange = { text.value = it },
        )
    }
}

image.png

可以看到,除了不能设置label之外,它与OutlinedTextField和TextField的使用方法基本一样

2. 显示样式

话不多说,由于TextField和BasicTextField的参数基本一样,我们就以TextField为例子,先看源码:

@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,// hint,输入为空是显示的文本
    leadingIcon: @Composable (() -> Unit)? = null,// 显示在文本字段容器开头的图标
    trailingIcon: @Composable (() -> Unit)? = null,// 显示在文本字段容器末尾的图标
    isError: Boolean = false,// 指示文本字段的当前值是否错误
    visualTransformation: VisualTransformation = VisualTransformation.None,// 转换输入value的可视表示形式
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,// 配置的软件键盘选项
    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 TestText() {
    val text = remember {
        mutableStateOf("你好, 沐枫")
    }
    Box(modifier = Modifier.size(width = 200.dp, height = 50.dp)) {
        TextField(
            value = text.value,
            onValueChange = { text.value = it },
            maxLines = 2,
            textStyle = TextStyle(color = Color.Red, fontWeight = FontWeight.Bold),
            modifier = Modifier.padding(20.dp)
        )
    }
}

看一下运行效果:

image.png

3. 键盘选项

设置键盘选项用到的是TextField的keyboardOptions参数,参数类型是KeyboardOptions,类型第一次见? 先看源码:

@Immutable
class KeyboardOptions constructor(
    val capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
    val autoCorrect: Boolean = true,
    val keyboardType: KeyboardType = KeyboardType.Text,
    val imeAction: ImeAction = ImeAction.Default
){
    companion object {
        /**
         * Default [KeyboardOptions]. Please see parameter descriptions for default values.
         */
        val Default = KeyboardOptions()
    }
}

1. capitalization

capitalization参数的类型为KeyboardCapitalization, 先看源码

inline class KeyboardCapitalization internal constructor(internal val value: Int) {
    companion object {
        // 不自动大写文本
        val None = KeyboardCapitalization(0)
        // 所有字符大写
        val Characters = KeyboardCapitalization(1)
        // 每个单词首字母大写
        val Words = KeyboardCapitalization(2)
        // 每个句子的首字母大写
        val Sentences = KeyboardCapitalization(3)
    }
}

2. autoCorrect

autoCorrect参数:通知键盘是否启用自动更正,autoCorrect仅适用于基于文本的KeyboardType,例如Email、Uri,它不会应用于Number

3.keyboardType

keyboardType参数的类型为KeyboardType,用于设置键盘类型:

inline class KeyboardType internal constructor(@Suppress("unused") private val value: Int) {
    companion object {
        // 用于请求显示常规键盘的IME的键盘类型
        val Text: KeyboardType = KeyboardType(1)
        // 用于请求能够输入ASCII字符
        val Ascii: KeyboardType = KeyboardType(2)
        // 输入数字
        val Number: KeyboardType = KeyboardType(3)
        // 输入电话号码
        val Phone: KeyboardType = KeyboardType(4)
        // 输入URI
        val Uri: KeyboardType = KeyboardType(5)
        // 输入电子邮件底子
        val Email: KeyboardType = KeyboardType(6)
        // 输入密码
        val Password: KeyboardType = KeyboardType(7)
        // 输入数字密码
        val NumberPassword: KeyboardType = KeyboardType(8)
    }
}

4. imeAction

imeAction的参数类型是ImeAction, 键盘的回车的类型,先看源码:

inline class ImeAction internal constructor(@Suppress("unused") private val value: Int) {
    companion object {
        // 使用平台和键盘默认设置
        val Default: ImeAction = ImeAction(1)
        // 不执行任何操作, 默认是换行
        val None: ImeAction = ImeAction(0)
        // 转到输入中文本目标, 访问Uri
        val Go: ImeAction = ImeAction(2)
        // 搜索
        val Search: ImeAction = ImeAction(3)
        // 发送
        val Send: ImeAction = ImeAction(4)
        // 返回到先前的输入
        val Previous: ImeAction = ImeAction(5)
        // 移至表单的下一个字段,
        val Next: ImeAction = ImeAction(6)
        // 输入完成操作
        val Done: ImeAction = ImeAction(7)
    }
}

举个栗子:

Box(modifier = Modifier.size(width = 200.dp, height = 50.dp)) {
    TextField(
        value = text.value,
        onValueChange = { text.value = it },
        maxLines = 2,
        keyboardOptions = KeyboardOptions(
            capitalization = KeyboardCapitalization.Characters, // 设置全部大写
            keyboardType = KeyboardType.Email,
            autoCorrect = true,
            imeAction = ImeAction.Search
        ),
        textStyle = TextStyle(color = Color.Red, fontWeight = FontWeight.Bold),
        modifier = Modifier.padding(20.dp)
    )
}

看一下运行效果:

image.png

5. 监听imeAction并执行

前面我们把IME的动作设置为Search,但是我们点击搜索按钮是没有效果的,因为我们还没有设置相应的交互。设置交互我们用到的是TextField中的keyboardActions参数,参数类型是KeyboardActions, 先看源码:

class KeyboardActions(
   
    val onDone: (KeyboardActionScope.() -> Unit)? = null,

    val onGo: (KeyboardActionScope.() -> Unit)? = null,

    val onNext: (KeyboardActionScope.() -> Unit)? = null,

    val onPrevious: (KeyboardActionScope.() -> Unit)? = null,

    val onSearch: (KeyboardActionScope.() -> Unit)? = null,

    val onSend: (KeyboardActionScope.() -> Unit)? = null
) {
    companion object {
        
        val Default: KeyboardActions = KeyboardActions()
    }
}

我们修改一下上面的例子:

val context = LocalContext.current
val text = remember {
    mutableStateOf("你好, 沐枫")
}
Box(modifier = Modifier.size(width = 200.dp, height = 50.dp)) {
    TextField(
        value = text.value,
        onValueChange = { text.value = it },
        maxLines = 2,
        keyboardOptions = KeyboardOptions(
            capitalization = KeyboardCapitalization.Characters, // 设置全部大写
            keyboardType = KeyboardType.Email,
            autoCorrect = true,
            imeAction = ImeAction.Search
        ),
        keyboardActions = KeyboardActions(
            onSearch = {
                Toast.makeText(context, "搜索: ${text.value}", Toast.LENGTH_SHORT).show()
            }
        ),
        textStyle = TextStyle(color = Color.Red, fontWeight = FontWeight.Bold),
        modifier = Modifier.padding(20.dp)
    )
}

查看运行结果:

image.png

最后

感谢你看到最后, 最后再说两点~
①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。
②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~
我是沐小枫,一个热爱学习、热爱编程的山东人

(文章内容仅供学习参考, 如有侵权,非常抱歉,请立即联系作者删除。)