鸿蒙原生应用 ArkUI 声明式:实验室首页的 2 列 Grid 与三状态色

App 23「实验室设备预约」首页(HomeTab),主题色 #0F766E 深青色(teal),4 个 Tab 分别为首页(🔬)、设备(🧪)、预约(📅)、我的(👤)。首页采用紧凑布局——Header(实验室设备)+ 5 分类 Chip(全部/光学/电子/机械/化学)+ SectionTitle(设备列表)+ 2 列 Grid 6 台设备卡(60×100% emoji 图标块 + 名称 + 型号规格 + 3 状态色:空闲绿/使用中橙/维护中红)。本篇基于 23-lab-booking/entry/src/main/ets/pages/HomeTab.ets(约 121 行)逐段拆解,附 4 张实机截图。

一、整体结构:3 块紧凑内容

App 23 首页是系列最紧凑的"设备列表"首页——3 个 @Builder 块:

build() {
  Column() {
    this.Header()
    Scroll() {
      Column({ space: 14 }) {
        this.ChipRow()
        this.SectionTitle('设备列表')
        this.DeviceGrid()
      }
      .width('100%')
      .padding({ left: D.pad, right: D.pad, top: 14, bottom: D.pad + this.safeBottom + 20 })
    }
    .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
  }
  .width('100%').height('100%').backgroundColor(C.bg)
}

3 块结构

  1. Header — "实验室设备"标题
  2. ChipRow — 5 分类胶囊(全部/光学/电子/机械/化学)
  3. SectionTitle('设备列表') + DeviceGrid — 2 列 Grid 6 台设备

与 App 21 问卷首页同构(3 块紧凑结构)——"设备列表 = 任务型列表"(用户来"找设备→预约"),不需要复杂首页。

主题色 #0F766E 深青色——实验室/科研/专业的调性(深青色接近"实验服蓝绿"、显微镜/试剂瓶的视觉联想)——与 App 19 青绿 #0D9488 同系但更深——**"深青 = 科研严肃、浅青 = 摄影清新"**同系不同调。

实验室设备首页首屏 · 实验室设备Header+5分类Chip(全部/光学/电子/机械/化学)+2列Grid 6台设备卡(空闲绿/使用中橙/维护中红状态色)

项目源码开源:https://gitee.com/codenestFlow/HarmonyOSHub

二、Header + ChipRow

Header 是"实验室设备"单行标题(无 Slogan——"工具型首页不配 Slogan")。

ChipRow 是 5 个分类(全部/光学/电子/机械/化学)的横滑胶囊:

@Builder ChipRow() {
  Scroll() {
    Row({ space: 10 }) {
      ForEach(this.cats, (cat: string, idx: number) => {
        Text(cat)
          .fontSize(13)
          .fontColor(this.activeCat === idx ? '#FFFFFF' : C.textSub)
          .padding({ left: 14, right: 14, top: 7, bottom: 7 })
          .backgroundColor(this.activeCat === idx ? C.primary : C.card)
          .borderRadius(16)
          .onClick(() => { this.activeCat = idx; })
      }, (cat: string) => cat)
    }
  }
  .scrollable(ScrollDirection.Horizontal).scrollBar(BarState.Off).width('100%')
}

5 个分类['全部', '光学', '电子', '机械', '化学']——实验室设备的 4 大分类(光学/电子/机械/化学是高校实验室的标准分类)。

@State activeCat: number = 0 默认选中"全部"——onClick 切选中态(activeCat === idx ? 深青底白字 : 白底灰字)。"假筛选"(同系列其他 Chip)——demo 未联动过滤,真实项目应加 filteredDevices()

borderRadius(16) 胶囊形——系列标准 Chip。

三、SectionTitle + DeviceGrid:2 列 Grid(本页核心)

SectionTitle 是"设备列表"标题(无右侧链接——简化版)。DeviceGrid 是 2 列 Grid 6 台设备

@Builder DeviceGrid() {
  Grid() {
    ForEach(this.devices, (d: Device) => {
      GridItem() {
        Column({ space: 8 }) {
          Row() {
            Text(d.emoji).fontSize(30)
          }
          .width('100%').height(60)
          .backgroundColor(C.cardSoft).borderRadius(D.rSm)
          .justifyContent(FlexAlign.Center)
          Text(d.name).fontSize(13).fontColor(C.text).maxLines(1)
            .textOverflow({ overflow: TextOverflow.Ellipsis }).width('100%')
          Text(d.spec).fontSize(11).fontColor(C.textDim).width('100%')
          Row() {
            Blank()
            Text(d.status).fontSize(11).fontColor(d.statusColor).fontWeight(FontWeight.Medium)
          }
          .width('100%')
        }
        .width('100%')
        .padding(10)
        .backgroundColor(C.card).borderRadius(D.rMd)
        .border({ width: 1, color: C.stroke })
        .onClick(() => { promptAction.showToast({ message: d.name }); })
      }
    }, (d: Device) => d.id.toString())
  }
  .columnsTemplate('1fr 1fr')
  .columnsGap(12)
  .rowsGap(12)
  .width('100%')
}

3.1 6 台设备的数据

private devices: Device[] = [
  { id: 1, emoji: '🔬', name: '高倍显微镜', spec: '1000x · 偏光', status: '空闲', statusColor: C.ok },
  { id: 2, emoji: '⚡', name: '示波器', spec: '200MHz · 4通道', status: '使用中', statusColor: C.warn },
  { id: 3, emoji: '🧪', name: '高效液相色谱仪', spec: 'UV检测器', status: '空闲', statusColor: C.ok },
  { id: 4, emoji: '🔩', name: '万能试验机', spec: '100kN', status: '维护中', statusColor: C.danger },
  { id: 5, emoji: '🔭', name: '光谱分析仪', spec: '200-800nm', status: '空闲', statusColor: C.ok },
  { id: 6, emoji: '📡', name: '网络分析仪', spec: '9kHz-6GHz', status: '使用中', statusColor: C.warn }
];

6 台设备覆盖 4 大分类

设备分类型号规格状态
🔬 高倍显微镜光学1000x · 偏光空闲(绿)
⚡ 示波器电子200MHz · 4通道使用中(橙)
🧪 高效液相色谱仪化学UV检测器空闲(绿)
🔩 万能试验机机械100kN维护中(红)
🔭 光谱分析仪光学200-800nm空闲(绿)
📡 网络分析仪电子9kHz-6GHz使用中(橙)

6 台设备的"真实实验室设备":显微镜/示波器/色谱仪/试验机/光谱仪/网络分析仪——都是真实的科研仪器(高校实验室常见设备)——"设备列表 = 真实科研环境"

3 状态分布:空闲 3 台(绿)/使用中 2 台(橙)/维护中 1 台(红)——"多空闲、少维护"是实验室常态

3.2 3 状态色映射

  • 空闲C.ok 绿(可预约)
  • 使用中C.warn 橙(被占用)
  • 维护中C.danger 红(不可用)

3 状态 3 色——**"空闲绿/使用橙/维护红"**是设备管理/会议室预约的标准色映射——与 App 14 场地(空闲/已约满)、App 22 投票(进行中/已结束)同款"状态色编码"。

3.3 设备卡的 4 层结构

每张设备卡 4 行(从上到下):

  1. 60 高 emoji 图标块C.cardSoft 浅灰底 + 🔬/⚡ 等)
  2. 设备名称(13sp 深色 + maxLines(1) 截断)
  3. 型号规格(11sp 灰)——"1000x · 偏光"等
  4. 状态(11sp 状态色 + 加粗 + 右对齐 Blank()

Blank() 把状态推到右下角——"名称左上、状态右下"的视觉节奏

maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }) 设备名截断——"高效液相色谱仪" 7 个字在 1 列内放不下——Ellipsis 省略(实际显示"高效液相色…")——"Grid 卡片文字必须截断"(列宽有限)。

3.4 2 列 Grid 布局

columnsTemplate('1fr 1fr') + columnsGap(12) + rowsGap(12)——2 列等宽 + 12vp 间隙——6 台设备排成 3 行 2 列。

"2 列 Grid vs 1 列列表"

  • 2 列(本页)——信息密度高(一屏看 4 台)、紧凑
  • 1 列(App 21/22)——信息完整(每行有按钮)、宽松

"设备列表用 2 列 Grid"是合理选择——设备卡信息少(名称+规格+状态),2 列紧凑展示——"信息少的列表用 Grid、信息多的列表用 List"

四、@State 与"紧凑首页"设计

HomeTab 只有 1 个 @StateactiveCat(分类 0-4)。其余数据 private 不可变。

App 23 首页是系列最紧凑的设备列表(3 块)——**"设备预约 = 找设备 → 看详情 → 预约"**的任务流——首页只负责"找设备"(列表展示)。

对比 App 14 运动场地预约首页(5 块:Hero/入口/周图/场地/排行)——App 14 首页"丰富"因为"运动"是内容型(场地推荐需要营销)——App 23 首页"紧凑"因为"实验室设备"是任务型(用户知道要什么设备)——**"业务类型决定首页复杂度"**再次验证。

五、设备状态与"预约意愿"的联动

App 23 首页的 3 状态直接决定"用户要不要点进详情预约":

状态 → 用户行为

  • 空闲(绿)→ "可以预约" → 点进详情 → 选时段 → 预约
  • 使用中(橙)→ "被占用了" → 可能等/换设备
  • 维护中(红)→ "坏了" → 换设备/联系管理员

"状态 = 预约意愿的引导"——用户扫一眼 Grid 就知道"哪台能约"——"状态色可视化 = 高效筛选"

真实项目的状态扩展

  • 已锁定(被特定用户预约,但还没用)
  • 预约中(未来时段已被预约)
  • 待维护(快需要维护)

"状态机"从 3 态扩展为 6 态——UI 只需改"状态名 + 状态色"(数据结构不变)——"状态可扩展性"是设备管理的基础

六、"设备状态色"与系列状态色的统一体系

App 23 首页的 3 状态色(空闲绿/使用中橙/维护中红)与系列其他 App 的状态色形成统一体系:

状态语义颜色出现位置
空闲/可用/进行中绿 C.okApp 23 设备、App 14 场地、App 22 投票
使用中/待处理/即将结束C.warnApp 23 设备、App 22 投票、App 15 环保
维护/已满/已结束C.dangerApp 23 设备、App 14 场地、App 16 商城

"绿=可用、橙=警示、红=不可用"是系列统一的状态色语义——读者在多个 App 间切换不会混淆(同一颜色永远代表同一类语义)——"跨 App 状态色一致性"是设计系统的一致性原则

"状态色映射"的工程实现(App 23 设备卡):

// 数据携带颜色(当前实现)
{ status: '空闲', statusColor: C.ok }
{ status: '使用中', statusColor: C.warn }
{ status: '维护中', statusColor: C.danger }

真实项目应抽成"状态 → 颜色"映射表

const STATUS_COLOR = {
  '空闲': C.ok, '使用中': C.warn, '维护中': C.danger,
  '已锁定': C.textDim, '待维护': C.warn
};
// 数据只存 status 字符串,颜色查表

"映射表代替数据携带颜色"——新增状态只改映射表一处,数据与视觉解耦。

七、"2 列 Grid" vs "1 列 List" 的选择标准

App 23 设备卡用 2 列 Grid(信息紧凑),对比系列其他列表:

App主列表布局卡片信息量
21 问卷问卷卡1 列 List中(emoji+标题+状态)
22 投票投票卡1 列 List中(emoji+标题+状态+剩余)
23 实验室设备卡2 列 Grid低(emoji+名称+规格+状态)
13 音乐项目卡1 列 List高(emoji+标题+标签+进度条)

"Grid vs List"选择标准

  • 信息少 + 数量多(设备 6 台、规格短)→ 2 列 Grid(一屏看更多)
  • 信息多 + 操作多(项目有进度条+按钮)→ 1 列 List(每行完整展示)

"卡片信息量决定布局"——信息少的卡片适合 Grid(高密度)、信息多的适合 List(完整性)

"2 列 Grid"的注意点

  • 卡片宽度减半 → 文字必须截断maxLines(1) + Ellipsis)
  • 状态/操作按钮空间小 → 只用"状态文字"不用按钮
  • 点击区域小 → 整卡可点(GridItem onClick)

App 23 设备卡的"Grid 三原则"(截断/无按钮/整卡可点)是 2 列 Grid 的标准实践。

实验室设备首页底部 · 选中"机械"分类Chip · 底部Tab栏

八、设备列表的"搜索与筛选"扩展

App 23 首页有分类 Chip(光学/电子/机械/化学)但无搜索框——真实设备管理应有**"分类 + 搜索"双筛选**:

// 真实项目的双筛选
private filteredDevices(): Device[] {
  let result = this.devices;
  if (this.activeCat > 0) {
    const catName = this.cats[this.activeCat];
    result = result.filter(d => this.catOf(d.id) === catName);
  }
  if (this.keyword.trim() !== '') {
    result = result.filter(d => d.name.includes(this.keyword.trim()) || d.spec.includes(this.keyword.trim()));
  }
  return result;
}

"分类 + 搜索"双条件过滤——activeCat(分类)+ keyword(搜索词)两个 @State 组合过滤——"多条件筛选"是设备/商品列表的标准

真实设备的"分类映射"

// 设备 → 分类映射
const DEVICE_CATEGORY: Record<number, string> = {
  1: '光学', 2: '电子', 3: '化学', 4: '机械', 5: '光学', 6: '电子'
};

"分类映射表"catOf() 一行查表——"设备与分类的关系数据化"(当前 demo 的 devices 数组没有 category 字段,是"假分类")——"分类字段缺失是'假筛选'的根源"——真实项目每个设备应有 category 字段。

实验室设备首页下部 · 选中"电子"分类Chip · 设备状态色

九、设备卡的"信息密度"与"科研设备命名"

App 23 的 6 台设备卡的"信息密度"设计:

每张卡 4 行信息的层级

  1. emoji 图标(30sp)——视觉锚点(最高信息密度)
  2. 设备名(13sp 加粗)——核心识别
  3. 规格(11sp 灰)——补充参数
  4. 状态(11sp 状态色)——行动信号

"图标 + 名称 + 规格 + 状态"4 层——从"最直观"到"最行动"的视觉递减——"科研设备卡"的信息架构

"科研设备命名"的专业性

  • 高倍显微镜(1000x · 偏光)
  • 高效液相色谱仪(UV 检测器)
  • 万能试验机(100kN)
  • 光谱分析仪(200-800nm)
  • 网络分析仪(9kHz-6GHz)

"型号规格"都是真实科研参数(倍率/通道/检测器/量程/频段)——"专业参数 = 科研可信度"——用户(科研人员)一眼看懂"这设备能干什么"——"设备卡是给专家看的"(对比 App 16 商品卡给消费者看价格,设备卡给科研人员看参数)。

实验室设备首页中段 · 选中"光学"分类Chip · Grid 6台设备卡完整呈现

十、"任务型首页"的 3 原则

App 23 首页是"任务型首页"的范本——3 个设计原则:

原则 1:分类优先(Chip 在最上方)——用户第一件事是"找分类"(光学/电子/机械/化学)——"分类 = 任务的第一步"

原则 2:列表高效(2 列 Grid 一屏 4 台)——用户快速扫设备——"一屏看到尽可能多"

原则 3:状态信号(状态色右对齐)——用户判断"哪台能约"——"状态 = 决策依据"

**"分类 → 扫视 → 决策"**是任务型首页的用户路径——与内容型首页(App 19 摄影"欣赏→收藏")的差异——任务型用户"目的明确"、内容型用户"浏览探索"。

读者做"任务型首页"时 3 原则自查

  • 分类在最上面了吗?
  • 列表一屏够多吗?
  • 关键状态一眼可见吗?

十一、总结

App 23 首页解析完毕。3 块紧凑结构 + 5 分类 Chip + 2 列 Grid 6 设备卡(3 状态色)是核心组件。"设备状态 → 预约意愿"的联动是设备预约场景的特色。**"2 列 Grid 紧凑设备列表"是任务型首页的范本。"Grid vs List 选择标准"、"分类映射表"、"任务型首页 3 原则"**是真实项目的关键改进。

配图

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐