前言
上一课学习了状态提升,掌握单向数据流:父传数据、子传事件,抽离可复用无状态组件。
本课学习文本输入框 TextField ,处理字符串类型状态,实现用户输入实时绑定。
核心要点:文本输入属于高频可变状态,理解 mutableStateOf 字符串状态、输入值双向绑定,掌握基础输入框。
前置:完成1~5课,掌握remember、状态提升、基础布局
一、完整可运行示例源码
kotlin
package com.example.composefirst
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TextFieldDemoPage()
}
}
}
@Composable
fun TextFieldDemoPage() {
// 字符串状态,初始为空字符串
var inputText by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(20.dp)) {
TextField(
value = inputText,
onValueChange = { newValue ->
inputText = newValue
},
label = { Text("请输入内容") }
)
Spacer(modifier = Modifier.height(16.dp))
Text(text = "你输入的内容:$inputText")
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { inputText = "" }) {
Text("清空输入")
}
}
}
@Preview
@Composable
fun TextFieldPreview() {
TextFieldDemoPage()
}
二、逐行代码解读
- var inputText by remember { mutableStateOf("") }
字符串状态,使用 mutableStateOf ,可以存放任意类型(字符串、对象等)。
之前数字我们用 mutableIntStateOf ,字符串没有专用简写,通用使用 mutableStateOf 。
remember 保证重组时不会丢失输入内容。
- TextField核心两个参数
kotlin
TextField(
value = inputText,
onValueChange = { newValue -> inputText = newValue }
)
- value :输入框当前显示的值,来自状态变量,单向数据源;
- onValueChange :用户打字时不断回调,参数 newValue 是用户最新输入文本;
我们在回调里把新值赋值给 inputText ,实现双向绑定效果。
底层原理:不是真正的双向绑定。用户输入 → onValueChange修改状态 → 状态改变触发重组 → value更新到输入框。
- label = { Text("请输入内容") }
悬浮提示文字,Material3规范,输入框未输入时淡色提示,点击输入后上浮。 - 清空按钮逻辑
点击按钮直接把 inputText = "" ,状态清空,自动重组,输入框内容同步清空。
体现Compose核心:修改状态,UI自动同步。
三、拓展:抽成无状态组件(复用+状态提升)
真实开发,输入框组件抽离,状态放在父组件:
kotlin
@Composable
fun TextFieldDemoPage() {
var inputText by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(20.dp)) {
InputField(
value = inputText,
onValueChange = { inputText = it }
)
Spacer(modifier = Modifier.height(16.dp))
Text("输入内容:$inputText")
}
}
// 无状态输入框子组件
@Composable
fun InputField(value: String, onValueChange: (String) -> Unit) {
TextField(
value = value,
onValueChange = onValueChange,
label = { Text("请输入内容") }
)
}
解读:子组件 InputField 没有remember,只接收value和回调,符合状态提升思想,多处页面可以复用这个输入框。
四、综合练习题
填空题
- 存储字符串类型状态,使用 remember 配合________。
- TextField中,________参数代表输入框当前展示的文本。
- 用户输入字符时,________回调会持续返回最新输入字符串。
答案与解析
- mutableStateOf ;解析:mutableStateOf是通用状态,字符串、自定义对象都可以使用。整型有专用mutableIntStateOf。
- value ;解析:输入框显示内容由value状态驱动。
- onValueChange ;解析:用户每输入、删除字符,都会触发该回调,带回最新文本。
判断题
- TextField不需要onValueChange,只写value就可以正常输入文字。()
答案:错误。理由:value是只读展示。不写onValueChange,无法更新状态,输入框会无法输入。
- mutableStateOf可以存放字符串,也可以存放自定义数据类对象。()
答案:正确。理由:mutableStateOf是通用泛型状态,支持任意类型。
- 状态提升后的输入框子组件,内部依然可以写remember保存输入文本。()
答案:错误。理由:状态提升方案,子组件为无状态组件,状态统一由父组件管理。
简答题
- Compose的TextField,是真正双向绑定吗?简述工作流程。
参考答案:
不是传统意义双向绑定。用户输入文字触发onValueChange,修改上层状态;状态变更触发重组,把新value渲染到输入框。本质还是单向数据流。
代码实操题
改造代码:增加判断,如果输入文本超过10个字,在下方提示「文字过长」,否则提示「输入正常」。写出完整TextFieldDemoPage。参考答案
kotlin
@Composable
fun TextFieldDemoPage() {
var inputText by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(20.dp)) {
TextField(
value = inputText,
onValueChange = { inputText = it },
label = { Text("请输入内容") }
)
Spacer(modifier = Modifier.height(16.dp))
if(inputText.length > 10){
Text("文字过长")
}else{
Text("输入正常")
}
}
}
解析:读取状态字符串长度,利用if条件渲染,状态变化自动刷新提示文本。
五、本课小结
- mutableStateOf 通用状态,适合字符串、对象;
- TextField依靠 value + onValueChange 完成输入交互;
- 可以把输入框抽为无状态组件,使用状态提升;
- 用户输入修改状态,状态驱动界面刷新。
下一课:if条件渲染 + 列表基础(LazyColumn)。