HarmonyOS7 @Builder 把重复 UI 收起来:别急着拆组件

一张适合技术文章开篇的 sketch-notes 风格框架图,主题是 HarmonyOS 7 中 `

前言

页面里重复三次以上的标题栏、设置行、状态标签,复制粘贴肯定能跑,但后面改样式会很痛苦。

这时候很多人会立刻拆组件。我的习惯是先判断:这个 UI 片段是不是只在当前页面复用?有没有独立状态?会不会跨页面使用?如果答案都偏轻,用 @Builder 更合适。

@Builder 适合收起当前组件里的局部重复,不是所有组件拆分的替代品。

一张 sketch-notes 风格的对比表插图,内容是 "直接复制 / @Builder / 独立

为什么这个问题经常被写乱

@Builder 把重复 UI 收起来 这类内容很容易被写成“代码能跑就算讲完了”,但对初学者来说,这恰恰是最不够的地方。真正让人卡住的,往往不是某个组件名记不住,而是不知道这段代码为什么要这样拆、状态为什么要这样放、以后需求变化时应该从哪里改。

所以这篇文章不只想给你一个能跑的例子,更想把背后的判断过程讲清楚。你只要把这个判断过程吃透,后面自己改页面、补需求、查问题时,心里会稳很多。

Builder 和组件怎么选

写法适合场景代价
直接复制一两处临时 UI后期样式容易漂移
@Builder同页面局部重复不适合承载复杂业务状态
独立组件多页面复用、有明确接口命名和参数要设计清楚

设置页是 @Builder 很适合的场景:分组标题、普通设置行、开关设置行都很像,但还没必要拆成一堆文件。

复制粘贴省的是当下几分钟,后面统一改样式时会还回来。

先把页面目标想清楚

一张 sketch-notes 风格的流程图,表现写页面前的判断过程:先想清楚页面目标和用户最在意的

在真正写代码之前,先别急着盯着 API。更有用的做法是先想清楚:这个页面到底想解决什么问题,用户最在意的反馈是什么,哪些状态必须一直保持一致。

当你先把这条主线想明白,再回头看组件和状态设计,很多选择都会顺理成章。对小白来说,这一步尤其重要,因为它能帮你从“照着抄”慢慢过渡到“看得懂、改得动”。

完整 ArkUI 示例

下面这个设置页用三个 @Builder 收起重复 UI:分组标题、普通设置行、开关设置行。

@Entry
@Component
struct SettingsBuilderPage {
  @State pushEnabled: boolean = true
  @State useCellular: boolean = false

  @Builder
  SectionTitle(title: string) {
    Text(title)
      .fontSize(13)
      .fontColor('#888888')
      .width('100%')
      .padding({ left: 4, top: 12, bottom: 6 })
  }

  @Builder
  SettingRow(title: string, desc: string, value: string) {
    Row() {
      Column({ space: 4 }) {
        Text(title).fontSize(16).fontColor('#222222')
        Text(desc).fontSize(12).fontColor('#888888').maxLines(1)
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
      Text(value).fontSize(14).fontColor('#666666')
      Text('>').fontSize(16).fontColor('#BBBBBB').margin({ left: 6 })
    }
    .padding(14)
    .backgroundColor(Color.White)
  }

  @Builder
  SwitchRow(title: string, desc: string, enabled: boolean, onChange: (value: boolean) => void) {
    Row() {
      Column({ space: 4 }) {
        Text(title).fontSize(16)
        Text(desc).fontSize(12).fontColor('#888888')
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)
      Toggle({ type: ToggleType.Switch, isOn: enabled })
        .onChange((value: boolean) => onChange(value))
    }
    .padding(14)
    .backgroundColor(Color.White)
  }

  build() {
    Column() {
      this.SectionTitle('账号')
      this.SettingRow('个人资料', '头像、昵称和简介', '去完善')
      this.SettingRow('登录设备', '查看最近登录的手机和平板', '2 台')

      this.SectionTitle('通知')
      this.SwitchRow('消息推送', '订单和系统通知会及时提醒', this.pushEnabled, (value: boolean) => {
        this.pushEnabled = value
      })
      this.SwitchRow('使用蜂窝网络同步', '非 Wi-Fi 环境也同步草稿', this.useCellular, (value: boolean) => {
        this.useCellular = value
      })
    }
    .padding(16)
    .backgroundColor('#F5F7FA')
  }
}

把关键代码一段段拆开

SectionTitle 是最轻的 Builder,只接收一个标题。它把字号、颜色、间距固定住,后面设置页分组多了也不会样式漂移。

SettingRow 负责普通可点击设置项。左侧是标题和说明,右侧是当前值和箭头。layoutWeight(1) 让左侧说明占剩余空间,右侧值不会被长文案挤掉。

SwitchRow 比普通行多一个开关状态和回调。这里没有让 Builder 自己保存状态,而是通过 enabledonChange 把状态交回页面。这样状态来源仍然清楚。

这三个 Builder 都只服务当前页面。如果以后多个页面都要用同样的设置行,再考虑抽成 SettingRowComponent

Builder 不适合装太多业务

如果一个 UI 片段开始有自己的生命周期、网络请求、复杂状态,继续塞在 @Builder 里就不合适了。那时候它已经不是“局部模板”,而是一个真正的业务组件。

参数也别太多。一个 Builder 如果传了七八个参数,读调用处会很费劲。可以先合成一个配置对象,或者直接拆组件。

新手最容易踩的坑

这一类示例最容易让人产生错觉:界面出来了,就以为已经掌握了。其实真正容易出问题的地方,通常都在效果之外,比如状态有没有收拢、失败后怎么兜底、以后要扩展时会不会牵一发动全身。

所以你练这篇内容时,别只看“现在能不能跑”,还要继续看“以后好不好改”。能把这个习惯养起来,你写出来的页面会比单纯照着示例拼出来的页面稳很多。

放进真实项目还要补什么

示例代码的重点是把核心思路讲明白,所以很多工程化细节会故意省掉。真正落到项目里时,你通常还要继续补接口联动、异常处理、边界保护、资源抽离,以及和其他页面状态之间的配合。

写在最后

比较稳的做法是分三步走:先把结构和职责立住,再把真实业务接进去,最后再优化视觉和交互体验。这样改出来的页面不只是“能演示”,而是真的更接近可以长期维护的业务代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值