一、鸿蒙UI组件库概述

大家好,我是老张。做鸿蒙开发这些年,我最大的感触就是——组件库这东西,真的是「用的时候觉得理所当然,自己写的时候才知道坑有多深」。今天咱们就来聊聊组件库的那些事儿。

1.1 什么是组件库

说白了,组件库就是一堆可复用的UI零件。你想想看,一个App里有多少按钮、列表、弹窗?如果每个页面都重新写一遍,那不得累死?

组件库把这些常用的界面元素封装好,你拿来就能用。就像乐高积木,每个组件都是一个标准件,拼在一起就是一个完整的应用。

在鸿蒙里,组件库可以是系统自带的,比如ButtonTextList这些。也可以是我们自己封装的,比如一个带图标的卡片、一个自定义的导航栏。我个人习惯把业务相关的UI都抽成组件,这样后期维护起来轻松很多。

核心要点:组件库 = 可复用的UI单元 + 标准化的接口 + 灵活的配置

1.2 组件库的价值

我在项目中遇到过这么一件事:有个页面需要展示用户信息卡片,设计稿改了三次,每次都要改十几个文件。后来我把卡片抽成组件,改一个地方就全搞定了。这就是组件库的价值。

具体来说,组件库能带来这些好处:

  • 开发效率翻倍——不用重复造轮子,写一次到处用
  • 一致性有保障——所有页面用同一套组件,风格统一
  • 维护成本降低——改一个组件,所有引用它的地方都生效
  • 团队协作顺畅——大家用同一套规范,代码风格统一

你想想看,如果一个团队五个人,每个人写的按钮样式都不一样,那画面太美我不敢看。组件库就是解决这个问题的。

1.3 鸿蒙ArkUI框架简介

ArkUI是鸿蒙的原生UI框架。嗯,这里要注意,它和Android的XML布局、iOS的Storyboard都不一样。ArkUI用的是声明式语法,说白了就是「你想要什么,直接说就行」。

举个例子:

@Component
struct MyButton {
  build() {
    Button('点击我')
      .backgroundColor('#007AFF')
      .borderRadius(8)
      .padding({ left: 16, right: 16, top: 8, bottom: 8 })
  }
}

看到没?代码就是UI,UI就是代码。没有单独的布局文件,没有繁琐的findViewById。我个人觉得这种方式特别直观,尤其是做自定义组件的时候,逻辑和视图在一起,改起来很方便。

ArkUI的核心概念其实就三个:

概念 说明 类比
@Component 声明这是一个组件 就像盖房子用的砖
build() 描述组件的UI结构 砖怎么摆放
@State/@Prop 管理组件的数据状态 砖的颜色、大小

为什么会这样设计?因为鸿蒙要支持多设备——手机、平板、手表、电视。如果还用传统的命令式UI,适配起来会非常痛苦。声明式UI的好处是,你只管描述「长什么样」,框架负责「怎么画出来」。

1.4 自定义组件开发流程

好了,理论说完了,咱们来点实际的。自定义组件到底怎么搞?我总结了一个四步法:

  1. 分析需求——搞清楚这个组件要干什么,有哪些状态
  2. 设计接口——定义好输入参数(@Prop)和输出事件(@Event)
  3. 实现UI——用ArkUI的组件拼出界面
  4. 测试验证——在不同场景下跑一跑,看看有没有bug

我的经验:第一步最容易被忽略。我曾经直接上手写代码,结果写到一半发现需求理解错了,全部重来。所以,先想清楚再动手,能省很多时间。

举个完整的例子。假设我们要做一个「带角标的按钮」:

@Component
struct BadgeButton {
  @Prop label: string = '按钮'
  @Prop badgeCount: number = 0
  @State private showBadge: boolean = false

  build() {
    Stack() {
      Button(this.label)
        .onClick(() => {
          this.showBadge = !this.showBadge
        })
      
      if (this.showBadge && this.badgeCount > 0) {
        Text(String(this.badgeCount))
          .backgroundColor('#FF3B30')
          .fontSize(12)
          .width(20)
          .height(20)
          .textAlign(TextAlign.Center)
          .borderRadius(10)
          .position({ top: -5, right: -5 })
      }
    }
  }
}

这个组件接收两个参数:按钮文字和角标数字。点击按钮可以切换角标的显示状态。你看,代码量不大,但功能完整。

避坑指南:我曾经在自定义组件里直接修改了父组件的状态,结果导致数据流混乱,调试了一整天。记住:子组件永远不要直接修改父组件的状态,要通过事件回调通知父组件去改。

最后说一句,自定义组件不是越复杂越好。如果一个组件超过200行代码,我建议你考虑拆分成更小的子组件。保持每个组件的职责单一,这才是好设计。

好了,这一章就到这里。下一章咱们会手把手写一个完整的自定义组件,从零开始,一步步来。