ArkUI 基础控件(对照 Compose):从 Text/Button/Toggle 练出组件边界

上一篇我们先用 RowColumnStack 搭了一个第一屏骨架。页面能摆出来以后,这篇来讲最常见的基础控件写顺:文字、按钮、开关。

这三个控件看起来很简单,但它们刚好覆盖 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)
  }
}

这段代码的实际显示效果:

ArkUI 通知设置卡片示意图
这段代码里有三条边界:

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("保存设置")
    }
  }
}

Compose 通知设置卡片示意图
两边代码长得不完全一样,但这张卡片的组织方式是一样的:

  • 外层 Column 管卡片边界:宽度、背景、圆角、内边距。
  • 内层 Row 管一行里的排布:左侧文案,右侧开关。
  • Text 管信息层级。
  • Toggle / Switch 管二值状态。
  • Button 管一次性动作。

如果你只记 API 名字,很容易把 Toggle 写成“另一个 Button”;如果你按控件语义理解,后面写设置页、列表项、表单项都会顺很多。

Text:不要只当“显示字符串”

很多初学者写 Text 时只关心内容能不能显示。实际项目里,Text 至少承担三层含义:

文本角色 ArkUI 常见属性 Compose 常见参数/Modifier 写法重点
标题 .fontSize().fontWeight() fontSizefontWeight 表达信息层级,不要只靠颜色变深
说明 .fontColor().opacity().margin() colormodifier.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:它表达的是“当前状态”

ToggleSwitch 最容易被误用。它不是“点一下执行某件事”,而是“这个设置现在处于开还是关”。

在 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

上一篇