上一篇我们先用 Row、Column、Stack 搭了一个第一屏骨架。页面能摆出来以后,这篇来讲最常见的基础控件写顺:文字、按钮、开关。
这三个控件看起来很简单,但它们刚好覆盖 UI 开发里最基础的三类动作:
Text:展示信息,也承担层级、强调、说明文字的语义。Button:触发一次明确动作,比如保存、提交、刷新。Toggle/Switch:表达一个可持续的二值状态,比如是否开启通知。
如果这三类控件的边界没写清楚,后面写列表、表单、设置页、组件库都会越来越乱。先看一个小例子:做一张“通知设置卡片”。
先写 ArkUI:一张设置卡片里放 Text、Button、Toggle
这个例子只做一件事:展示一个设置项,允许用户开关通知,再提供一个按钮触发保存动作。
@Component
struct NotifySettingCard {
@State enableNotify: boolean = true
build() {
Column() {
Row() {
Column() {
Text('消息通知')
.fontSize(18)
.fontWeight(FontWeight.Medium)
Text(this.enableNotify ? '已开启,重要消息会及时提醒' : '已关闭,你可能错过重要消息')
.fontSize(13)
.fontColor('#6B7280')
.margin({ top: 6 })
}
.layoutWeight(1)
Toggle({ type: ToggleType.Switch, isOn: this.enableNotify })
.onChange((isOn: boolean) => {
this.enableNotify = isOn
})
}
.width('100%')
.alignItems(VerticalAlign.Center)
Button('保存设置')
.width('100%')
.height(44)
.margin({ top: 16 })
.onClick(() => {
console.info(`save notify setting: ${this.enableNotify}`)
})
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
}
}
这段代码的实际显示效果:

1. Text 只负责“展示什么”和“怎样展示”。标题和说明文字分开写,不要把一大段文本塞进一个 Text 里再靠换行和空格控制层级。 2. Toggle 负责改变 enableNotify 这个状态。它不是按钮的替代品,因为它表达的是“当前开/关”,不是“点一下执行一次动作”。 3. Button 负责触发保存动作。它读取当前状态,但不直接承担状态切换。
这就是基础控件最重要的训练:先把控件语义分清,再写属性链。
再看 Compose:同一张卡片的 Android 参照
这里继续拿 Jetpack Compose 做参照。Compose 是 Android 的声明式 UI 框架,和 ArkUI 一样,都是把 UI 结构、样式和交互写在组件函数/组件结构里。
@Composable
fun NotifySettingCard() {
var enableNotify by remember { mutableStateOf(true) }
Column(
modifier = Modifier
.fillMaxWidth()
.background(Color.White, RoundedCornerShape(12.dp))
.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = "消息通知",
fontSize = 18.sp,
fontWeight = FontWeight.Medium
)
Text(
text = if (enableNotify) "已开启,重要消息会及时提醒" else "已关闭,你可能错过重要消息",
fontSize = 13.sp,
color = Color(0xFF6B7280),
modifier = Modifier.padding(top = 6.dp)
)
}
Switch(
checked = enableNotify,
onCheckedChange = { enableNotify = it }
)
}
Button(
onClick = { Log.d("NotifySetting", "save notify setting: $enableNotify") },
modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(top = 16.dp)
) {
Text("保存设置")
}
}
}

- 外层
Column管卡片边界:宽度、背景、圆角、内边距。 - 内层
Row管一行里的排布:左侧文案,右侧开关。 Text管信息层级。Toggle/Switch管二值状态。Button管一次性动作。
如果你只记 API 名字,很容易把 Toggle 写成“另一个 Button”;如果你按控件语义理解,后面写设置页、列表项、表单项都会顺很多。
Text:不要只当“显示字符串”
很多初学者写 Text 时只关心内容能不能显示。实际项目里,Text 至少承担三层含义:
| 文本角色 | ArkUI 常见属性 | Compose 常见参数/Modifier | 写法重点 |
|---|---|---|---|
| 标题 | .fontSize()、.fontWeight() |
fontSize、fontWeight |
表达信息层级,不要只靠颜色变深 |
| 说明 | .fontColor()、.opacity()、.margin() |
color、modifier.padding() |
放在标题下面,语气短,避免撑爆卡片 |
| 状态文案 | 根据状态切换字符串 | 根据 state 切换 text |
文案跟状态绑定,别写成散落的 if/else |
设置卡片里的第二个 Text 就是状态文案:enableNotify 变了,它的文字也跟着变。这个例子很小,但它已经开始触碰状态管理了。这里不展开 @State 的完整体系,只记住一点:状态先服务于具体 UI,再抽成更大的状态模型。
Button:先分清主动作和普通动作
按钮不是“可点击文字”。它代表一次明确动作,应该让读者一眼看出“点它会发生什么”。
ArkUI 里 Button('保存设置') 后面接 .onClick();Compose 里 Button(onClick = { ... }) { Text(...) }。两边写法不同,但判断标准一样:
- 按钮文案要是动作,不要写成模糊名词。
- 一个卡片里不要塞太多同级主按钮。
- 点击逻辑不要混进文本展示逻辑里。
- 如果按钮只是切换开关,它大概率应该是
Toggle/Switch,不是Button。
HarmonyOS sample 里的组件库示例也体现了这种分工:ButtonBuilder 把点击和长按手势挂在按钮上,再把样式变化交给属性 modifier;TextBuilder 主要处理文字展示属性。这个结构值得学习:交互属于控件,样式收敛在属性层。
Toggle / Switch:它表达的是“当前状态”
Toggle 和 Switch 最容易被误用。它不是“点一下执行某件事”,而是“这个设置现在处于开还是关”。
在 ArkUI 里:
Toggle({ type: ToggleType.Switch, isOn: this.enableNotify })
.onChange((isOn: boolean) => {
this.enableNotify = isOn
})
在 Compose 里:
Switch(
checked = enableNotify,
onCheckedChange = { enableNotify = it }
)
两边都把状态拆成两部分:当前值和变化回调。这个模式后面会反复出现:输入框、选择器、列表选中态、表单校验,都会沿着“value + onChange”的思路展开。
小结表:三类基础控件该怎么放
| 控件 | 负责什么 | 不该负责什么 | 常见错误 |
|---|---|---|---|
Text |
信息展示、层级、说明、状态文案 | 业务动作、复杂布局 | 用一个大 Text 塞完所有内容 |
Button |
一次性动作 | 持续状态 | 用按钮模拟开关 |
Toggle / Switch |
二值状态 | 保存/提交等一次性动作 | 只写点击,不展示当前状态 |
写 UI 时先问一句:这个东西是在展示信息、触发动作,还是表达状态?这个问题比“ArkUI 里对应哪个 Compose API”更重要。
Checklist:写完基础控件后检查 5 件事
- 文本是否有层级:标题、说明、状态文案是否分开。
- 按钮是否是动作:按钮文案能不能回答“点了会发生什么”。
- 开关是否有状态:是否能从界面看出当前是开还是关。
- 属性链是否集中:样式不要散在多个无关分支里。
- 状态是否收口:
onChange/onClick里只做当前组件应该负责的事。
参考素材
- Android:Text in Compose:https://developer.android.com/develop/ui/compose/text
- Android:Button in Compose:https://developer.android.com/develop/ui/compose/components/button
- Android:Switch in Compose:https://developer.android.com/develop/ui/compose/components/switch
- HarmonyOS:ArkUI 声明式 UI 开发框架:https://developer.huawei.com/consumer/cn/arkui/
- HarmonyOS:ArkUI Button 指南:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-common-components-button-V5
- HarmonyOS:HarmonyOS Samples 组件库示例:https://gitcode.com/HarmonyOS_Samples/sample_in_harmonyos
// Kai@CodeHubble
// 观测坐标:Android-HarmonyOS/2026-05-17