使用 Compose + ViewModel + Flow 进行 GUI 编程
课题
- 程序界面由3个文本编辑框和1个文本标签组成。
- 要求文本标签实时显示3个文本编辑框所输入的数字之和。
- 文本编辑框输入的不是合法数字时,将其值视为0。
- 3个文本编辑框的初值分别为1,2,3。
创建工程
打开 Android Studio,File / New / Project...
在 New Project 向导的第1页,选择 Empty Compose Activity
在向导的第2页 Name 填上 Compose Example
在向导的第4页点击 Finish 按钮创建工程
ViewModel
在 com.example.composeexample 包中添加 NumbersViewModel 类
class NumbersViewModel : ViewModel() {
val number1 = MutableStateFlow("1")
val number2 = MutableStateFlow("2")
val number3 = MutableStateFlow("3")
val result = combine(number1, number2, number3) { n1, n2, n3 ->
((n1.toIntOrNull() ?: 0) + (n2.toIntOrNull() ?: 0) + (n3.toIntOrNull() ?: 0)).toString()
}
}
配置 UI
打开 MainActivity.kt,将内容修改为
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeExampleTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
AddNumbers()
}
}
}
}
}
@Composable
fun LeftText(
text: String = "",
) {
Text(
text = text,
modifier = Modifier.width(40.dp),
textAlign = TextAlign.Center,
)
}
@Composable
fun RightTextField(
value: String,
onValueChange: (String) -> Unit,
readOnly: Boolean = false,
) {
TextField(
value = value,
onValueChange = onValueChange,
readOnly = readOnly,
modifier = Modifier.width(200.dp),
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.End)
)
}
@Composable
fun AddNumbers() {
val vm = remember { NumbersViewModel() }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Row {
LeftText()
RightTextField(
value = vm.number1.collectAsState().value,
onValueChange = { vm.number1.value = it },
)
}
Row {
LeftText()
RightTextField(
value = vm.number2.collectAsState().value,
onValueChange = { vm.number2.value = it }
)
}
Row(verticalAlignment = Alignment.CenterVertically) {
LeftText("+")
RightTextField(
value = vm.number3.collectAsState().value,
onValueChange = { vm.number3.value = it }
)
}
Row {
LeftText()
RightTextField(
value = vm.result.collectAsState("").value,
onValueChange = {},
readOnly = true
)
}
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
ComposeExampleTheme {
AddNumbers()
}
}