# 准备知识

# JetpackCompose 相比传统 XML+Java 的优势

  • 不需要多个 XML 和 Activity
  • 可组合函数负责更新和构建页面
  • 不需要通过 ID 来查找视图,而是通过视图来绑定
  • 与 Java+XML 的传统方式相兼容

# 使用 JetpackCompe 构建页面

在 Andorid Studio 中新建项目,选择 Empty Compose Activity 后点击 Next

[img]

  • 需要 API 21+
  • 只能使用 Kotlin 语言

# AndoridManifest.xml 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/my_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/my_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Profile"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Profile">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

application 内属性

  • android:icon App 的主图标
  • android:label 应用名称
  • android:roundIcon 应用背景图标
  • android:theme 应用的主题

activity 内属性:

  • android:name 应用启动后的主页面
  • android:label 应用名称
  • android:theme 应用的主题

# 资源引用

1
@[xxx]/[xxxx]
  • [xxx] 为引用资源的路径
  • [xxxx] 为引用资源的名称,不包括文件后缀

如在 string.xml 内定义的应用名称:

1
2
3
<resources>
<string name="app_name">Candy\'s Profile</string>
</resources>

在其他位置的引用可以使用:

1
@string/app_name

# 依赖项

build.gradle(:app) (注:作用域是 app) 下的 dependencies 组为依赖项,可以在这里添加你需要使用的库

# 案例 1 个人页面

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.candy.ui_test

import android.R.attr.text
import android.R.attr.top
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

@Composable
fun ProfilePage()
{
Card( //卡片
elevation = CardDefaults.cardElevation(defaultElevation = 8.dp), // 正确的写法 (适用于 Material 3)
// elevation = 8.dp, // 在 Material 2 中这是可以的
modifier = Modifier.height(600.dp) //设置卡片高度
// .fillMaxSize()
.padding(top = 150.dp, bottom = 50.dp, start = 16.dp, end = 16.dp)
)
{
Column( //一种列表布局
modifier = Modifier.fillMaxHeight()//先添加该属性,填满整个高度
.verticalScroll(rememberScrollState()), //列表垂直滚动 参数为记住列表滚动状态
horizontalAlignment = Alignment.CenterHorizontally, //列表水平居中
verticalArrangement = Arrangement.Center, //列表垂直居中 填满后生效
)
{
Image(
painter = painterResource(id = R.drawable.photo), //图片的画家,即为图片路径
contentDescription = "Candy", //图片的描述
modifier = Modifier.size(125.dp) //图片的尺寸
// .clip(CircleShape) //图片的纯圆修饰符
.clip(RoundedCornerShape(15)) //图片的圆角形状 单位int 50为纯圆
.border(
width = 1.dp, //图片的边框宽度
color = Color.White, //图片的边框颜色
shape = RoundedCornerShape(15) //图片的边框形状
), //图片的边框
contentScale = ContentScale.Crop //图片的裁剪方式
)

Text(
text = "Candy",
fontWeight = FontWeight.Bold, //字体加粗
fontSize = 30.sp, //字体大小
)
Text(
text = "@Candquarzy\uD83C\uDFF3\uFE0F\u200D⚧\uFE0F",
fontSize = 12.sp, //设置字体大小
)

Row(
horizontalArrangement = Arrangement.SpaceEvenly, //列表水平均匀排列
modifier = Modifier.fillMaxWidth() //填满整个宽度
.padding(16.dp) //添加外边距
)
{
ProfileData("5.28k", "粉丝") //调用函数
ProfileData("114", "关注") //调用函数
ProfileData("87", "动态") //调用函数
}

Row(
horizontalArrangement = Arrangement.SpaceEvenly, //列表水平均匀排列
modifier = Modifier.fillMaxWidth() //填满整个宽度
// .padding(16.dp) //添加外边距
)
{
ElevatedButton(
onClick = {
/* TODO */
})
{
Text(
text = "关注",
)
}

ElevatedButton(
onClick = {
/* TODO */
})
{
Text("私信")
}
}
}
}
}

@Composable
fun ProfileData(count: String, text: String) //函数 用于存储数据列表
{
Column(
horizontalAlignment = Alignment.CenterHorizontally, //列表水平居中
)
{
Text(
text = count,
fontWeight = FontWeight.SemiBold, //字体加粗
)
Text(
text = text,
)
}
}

@Preview(showBackground = true) //预览注解 + 显示背景
@Composable
fun ProfilePagePreview()
{
ProfilePage()
}

# 布局

# Column 垂直布局

1
import androidx.compose.foundation.layout.Column

一种纵向的列表布局

参数

  • verticalArrangement 垂直对齐方式 属性值为 Arrangement.[direction]
  • horizontalAlignment 水平对齐方式 属性值为 Alignment.[direction]
  • content

modifier 参数

  • .fillMaxSize/Widht/Height() 列表填满父容器 (宽度 / 高度)
  • .padding([int.dp]) 外边距
  • .margin([int.dp]) 内边距
  • .requiredHeight(Weight) 强制设置高度 / 宽度 (不受父高度影响强制设置)

# Row 水平布局

1
import androidx.compose.foundation.layout.Row

一种纵向的列表布局

参数

  • verticalArrangement 垂直对齐方式 属性值为 Arrangement.[direction]
  • horizontalAlignment 水平对齐方式 属性值为 Alignment.[direction]
  • content

modifier 参数

  • .fillMaxSize/Widht/Height() 列表填满父容器 (宽度 / 高度)
  • .padding([int.dp]) 外边距
  • .margin([int.dp]) 内边距
  • .requiredHeight(Weight) 强制设置高度 / 宽度 (不受父高度影响强制设置)

# Card 卡片布局

1
import androidx.compose.material3.Card

一种卡片形式的布局

参数

  • shape 卡片形状
  • colors 卡片颜色
  • elevation 卡片悬浮高度 (MD3: CardDefaults.cardElevation(defaultElevation = [int].dp) ; MD2: [int].dp ) int 值为阴影模糊程度
  • border 卡片边框线
  • content ?

modifier 参数

  • .fillMaxSize/Widht/Height() 列表填满父容器 (宽度 / 高度)
  • .padding([int.dp/sp]) 外边距 (可以分开设置 top bottom start end)
  • .height([int.dp]) 卡片高度
  • .weight([int.dp]) 卡片宽度
  • .requiredHeight(Weight) 强制设置高度 / 宽度 (不受父高度影响强制设置)

# 约束布局

1
import androidx.constraintlayout.compose.ConstraintLayout

一种使用 ID 来绑定组件的布局,可以更方便的定义组件所在页面中的位置

而在这种布局下, horizontalAlignmentverticalArrangement 不再可用

要使用约束布局,需要在 build.gradle 中添加依赖项:

1
implementation ("androidx.constraintlayout:constraintlayout-compose:1.1.1")

截至写这篇文章的时候,最新的版本为 1.1.1 Constraintlayout | Jetpack | Android Developers

要使用约束布局,需要按以下方式:

  1. 使用 createRefs() createRefFor() ConstraintLayout 中的每个可组合项创建引用
  2. 约束条件使用 Modifier.constrainAs() 修饰符提供的,该修饰符将引用作为参数,然后指定其约束条件
  3. 约束条件使用 linkTo() 方法指定
  4. parent 是一个屏幕位置,可用于指定对 ConstraintLayout 可组合项本身的约束条件

modifier 参数

.constrainAs([String id]) 控制

  • top.linkTo() 顶部链接到
  • buttom.linkTo() 底部链接到
  • start.linkTo() 起始处链接到
  • end.linkTo() 结尾处链接到
  • width 属性值 (如 Dimension.wrapContent*)

该项目中所有参数均为所设定的控件 ID 其中,parent 为父级,可以理解为屏幕

* 使用 Dimension.wrapContent 需要导入

1
import androidx.constraintlayout.compose.Dimension

# 约束布局的解耦合

优势:有助于实现横屏和竖屏的切换

  1. 首先需要导入一个盒子约束容器

  2. 在其内部定义一个变量,通过判断来判断用户当前为横屏还是竖屏,接着设置约束方法函数

    而在该约束容器内部的约束布局内的元素需要给 Modifier 注册.layoutId (“String”),并在约束方法中引用

比如导入

1
import androidx.compose.foundation.layout.BoxWithConstraints

BoxWithConstraints 约束盒子容器

image-20250531224810783

image-20250531224818174

# 约束方法

创建一个保护的成员函数

image-20250531224849275

image-20250531224855004

# Scaffold "脚手架" 布局

1
import androidx.compose.material3.Scaffold

Scaffold 是一种类似于框架一样的结构。它将界面的不同部分整合在一起,使其具有一致的外观和风格

  • topBar 应用的屏幕顶部应用栏
  • bottom 应用的屏幕底部应用栏
  • floatingActionButton 悬浮在屏幕右下角的按钮

Scaffold 会自动计算举例宽度,所以在该可组合函数内部要使用 innerPadding-> 来传入边距

一个架构实现,其中包含简单的顶部和底部应用栏,以及用于迭代计数器的悬浮操作按钮。框架的内部内容是用于说明组件的简单文本。

** 案例 (来自谷歌官方): **

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@Composable
fun ScaffoldExample() {
var presses by remember { mutableIntStateOf(0) }

Scaffold(
topBar = {
TopAppBar(
colors = topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
titleContentColor = MaterialTheme.colorScheme.primary,
),
title = {
Text("Top app bar")
}
)
},
bottomBar = {
BottomAppBar(
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.primary,
) {
Text(
modifier = Modifier
.fillMaxWidth(),
textAlign = TextAlign.Center,
text = "Bottom app bar",
)
}
},
floatingActionButton = {
FloatingActionButton(onClick = { presses++ }) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
}
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
Text(
modifier = Modifier.padding(8.dp),
text =
"""
This is an example of a scaffold. It uses the Scaffold composable's parameters to create a screen with a simple top app bar, bottom app bar, and floating action button.

It also contains some basic inner content, such as this text.

You have pressed the floating action button $presses times.
""".trimIndent(),
)
}
}
}

官方文档: Scaffold - Jetpack Compose | Android Developers

# LazyColumn / LazyRow "懒" 列 / 行布局

1
2
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow

这是一个可以扩展长度的容器,在该容器内的元素必须是动态长度

需要使用 item lambda 等遍历容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
val itemsList = (0..5).toList()
val itemsIndexedList = listOf("A", "B", "C")

@Composable
LazyColum(

)
{
items(itemsList){
Text(
text = "Item is ${it}",
)
}
}

# Box 盒子布局

1
import androidx.compose.foundation.layout.Box

可以层叠元素的盒子,类似于 HTML 中的 div 标签

# 控件

# Text 文本组件

1
import androidx.compose.material3.Text

一种显示文本的文本组件

参数

  • text 文本内容,类型为 String
  • color 文本颜色
  • fontSize([int].dp) 文字大小
  • fontStyle 文本风格?
  • fontWeight 字体粗细,由 FontWeight 类控制
  • fontFamily 字体家族,由 FontFamily 类控制
  • textAlign 文本对齐方式?

# Image 图像组件

1
import androidx.compose.foundation.Image

一种显示图像的组件

  • painter 画家 (图像路径)
  • contentDescription 图像的描述 (针对视障人士)
  • contentScale 图片的裁剪方式 (如填充横向 填充纵向等等)
  • alignment 对齐方式 (默认居中)
  • alpha 不透明度 (单位 Float)

** 官方文档: ** 加载图片 | Jetpack Compose | Android Developers

modifier 参数

  • .size 图片尺寸 / 大小 (单位 dp)
  • .clip 图片形状 [如 CircleShape 为纯圆,可以使用 RoundedCornerShape([int].dp) 自定义圆角]
  • .border 图片边框

** 官方文档: ** 自定义图片 | Jetpack Compose | Android Developers

# TextField 文本输入框

1
import androidx.compose.material3.TextField

一种用于让用户输入的文本框有多种样式可选

  • TextField 基础的默认的样式,样式为填充

  • OutlinedTextField 轮廓样式版本,无填充

  • SecureTextField 安全输入,用于输入密码等

  • value 输入框内的值

  • onValueChange 当输入框内容变更后执行

  • label 输入框提示值

以下是一个案例,当用户输入内容更新后将用户输入的内容输出在 UI 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var name_state by remember {
mutableStateOf("")
//使用remember和mutableStateOf创建一个可变状态变量
}

var name: String by rememberSaveable {
//使用rememberSaveable可以在页面旋转时保存数据
mutableStateOf("")
//使用remember和mutableStateOf创建一个可变状态变量
//只有这样在变化时才会进行页面重组
}

Column(
horizontalAlignment = Alignment.CenterHorizontally, //水平对齐居中
verticalArrangement = Arrangement.Center, //垂直对齐居中
modifier = Modifier.fillMaxSize(), //填充满屏幕
) {
Text("Hello $name"); //文本组件 将name的值复制给文本
//当name的值改变时,文本会自动更新(刷新界面)
Spacer(modifier = Modifier.height(20.dp)) //间隔组件,设置高度为20dp

TextField(
//文本输入框
value = name_state,
//原本文本框是无状态的,
// 然后使用remember和mutableStateOf创建了一个
// 可变状态变量name_state 并分配给它
onValueChange = {
//当输入框的值改变时调用
name_state = it //更新状态
},
label = {
Text("请输入:")
}
)
Button(
onClick = {
name = name_state //点击按钮时将输入框的值赋给name
}
)
{
Text(text = "显示")
}

官方文档: 配置文本字段 | Jetpack Compose | Android Developers

# Spacer 空行分隔符

1
import androidx.compose.foundation.layout.Spacer

modifier 参数

  • .size 大小
  • .weight 空行的宽度
  • .height 空行的高度

# Icon 图标组件

1
2
import androidx.compose.material3.Icon
import androidx.compose.material.icons.Icons //导入谷歌的图标类
  • imageVector 图标名 谷歌官方提供的图标都在 Icons. 类下
  • contentDescription 无障碍提示
  • tint 应用于 imageVector , 如果提供了 Color.[name] , 则不应用色调
1
import androidx.compose.material3.NavigationBar
  • containerColor 底部导航栏的背景色
  • contentColor 底部导航栏的文字 / 图标的颜色
1
import androidx.compose.material3.NavigationBarItem
  • selected 是否选中
  • onClick 点击事件,常用于导航跳转
  • icon 按钮图标
  • label 文本内容

这俩常用在一起,用于给 Scaffold 添加 bottomBar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
NavigationBar(
)
{
items.forEach {
item ->
NavigationBarItem(
selected = false,
onClick = {

},
icon = {
Icon( )
},
label = {
Text( )
}
)
}
}

通常来说会将图标和文字放在别处

  1. 创建一个包 model
  2. 新建一个 kotlin 类
  3. 在类中创建对象,并在导航栏中引用

# IconButton 按钮图标组件

1
import androidx.compose.material3.IconButton
  • onClick 点击事件
  • enabled 启用按钮 (默认为 true)
  • colors 按钮的颜色

可以在内部设置 Icon 图标和文字

1
2
3
4
5
6
7
8
9
10
11
12
13
IconButton(
onClick = {
//点击事件
}
)
{
Icon(
//图标设置
)
Text(
//显示文本设置
)
}

# Dialog 对话框组件

1
import androidx.compose.ui.window.Dialog
  • onDismissrequest 用户关闭对话框(例如点按对话框以外的任意位置)时调用
  • properties 一个 DialogProperties 实例,可提供一些额外的自定义范围
1
import androidx.compose.ui.window.DialogProperties //使用DialogProperties需要导入

# AlertDialog 提醒对话框组件

1
import androidx.compose.material3.AlertDialog

这是一个便捷的 API,用于创建一个简易的对话框,如取消确认等

  • title 对话框标题
  • text 对话框内说明文本
  • icon 对话框顶部显示的图标
  • onDismissrequest 用户关闭对话框(例如点按对话框以外的任意位置)时调用
  • dismissButton 用于关闭的可组合函数
  • confirmButton 用于确认的可组合函数

PixPin_2025-06-12_22-37-02

以下是谷歌官方案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Composable
fun AlertDialogExample(
onDismissRequest: () -> Unit,
onConfirmation: () -> Unit,
dialogTitle: String,
dialogText: String,
icon: ImageVector,
) {
AlertDialog(
icon = {
Icon(icon, contentDescription = "Example Icon")
},
title = {
Text(text = dialogTitle)
},
text = {
Text(text = dialogText)
},
onDismissRequest = {
onDismissRequest()
},
confirmButton = {
TextButton(
onClick = {
onConfirmation()
}
) {
Text("Confirm")
}
},
dismissButton = {
TextButton(
onClick = {
onDismissRequest()
}
) {
Text("Dismiss")
}
}
)
}

官方文档: 对话框 | Jetpack Compose | Android Developers

# xxxDivider 分割线组件

  • HorizontalDivider 水平分割线
  • VerticalDivider 垂直分割线

组件参数:

  • thickness 使用此参数指定分隔线的粗细。
  • color 使用此参数指定分隔线的颜色。

官方文档: 分隔线 | Jetpack Compose | Android Developers

# Chip 条状标签

1
2
import androidx.compose.material3.Chip
import androidx.compose.material3.ChipDefaults

有多种样式可选

  • onClick 设定点击状态

  • label 设定显示文字 需要 Composable 函数

  • selected 是否选中

  • leadingIcon 定义菜单项中前方显示的图标 需要 Compose 函数

  • trailingIcon 定义菜单项中后方显示的图标 需要 Compose 函数

PixPin_2025-06-12_22-47-41

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var select by remember { mutableStateOf(false) }

FilterChip(
onClick = {
select = !select
},
label = {
Text(
text = "about"
)
},
selected = select,
leadingIcon = {
if (select)
{
{
Icon(
/* ICON */
)
}
}
else
{
null
},
}
)

官方文档: 条状标签 | Jetpack Compose | Android Developers

  • expanded 菜单是否可见
  • onDismissRequest 处理菜单关闭
  • onClick 点击菜单项后执行
  • text 定义菜单项中显示的内容 需要 Compose 函数而不是 String
  • leadingIcon 定义菜单项中前方显示的图标 需要 Compose 函数
  • trailingIcon 定义菜单项中后方显示的图标 需要 Compose 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var menuExpanded by remember { mutableStateOf(false) }

IconButton(
onClick = {
menuExpanded = true
}
)
{
Icon(
/* ICON */
)
}
DropdownMenu(
expanded = menuExpanded,
onDismissRequest = {
menuExpanded = false
}
)
{
DropdownMenuItem(
onClick = {
/* TODO */
},
text = {
Text(
text = "关于"
)
},
leadingIcon = {
Icon(
/* ICON */
)
}
)
}

官方文档: 菜单 | Jetpack Compose | Android Developers

#

# Modifier 修饰符

Compose 修饰符列表 | Jetpack Compose | Android Developers

# 状态

在 Jetpack 中,我们需要使用 remember 关键字来设置一个可变状态

# 可变状态

# remember

remember 是一个 Composable 函数,它用于在重组过程中记住一个值。当一个 Composable 重组时, remember 会返回它在上次重组时记住的相同值。如果没有 remember , 每次重组时,局部变量都会被重新初始化而导致状态丢失

若需使用 remember 需要导入:

1
2
3
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.runtime.remember
# mutableStateOf

mutableStateOf 是一个函数,用于创建一个 MutableState 实例。其接收一个初始值,并返回一个可观察的对象。当 MutableStatevalue 改变时,所有读取该 value 的 Composable 都会被标记为需要重组

在函数体中, mutableStateOf 为创建一个可观察的 MutableState<T> 对象。当 MutableState 中的值改变时,Compose 会自动触发依赖该状态的可组合函数的重组

声明 MutableState 对象的方法有如下 (default 为默认值):

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var name_state by remember {
mutableStateOf("") //使用remember和mutableStateOf创建一个可变状态变量
}

Text("Hello $name_state")
// 假设我们要设定让用户输入的内容更改到该Text上:
OutlinedTextField( //文本输入框
value = name_state,s
//原本文本框是无状态的,
// 然后我们使用remember和mutableStateOf创建了一个
// 可变状态变量name_state 并分配给它
onValueChange = {
//当输入框的值改变时调用
name_state = it //更新状态
},
label = {
Text("请输入:")
} //标签文本
)

官方文档: 状态和 Jetpack Compose | Android Developers

# 导航

导航 | App architecture | Android Developers

更新于 阅读次数