鸿蒙应用开发实战【22】— 空状态引导页设计与实现

前言

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
在这里插入图片描述

用户首次打开号码助手时,数据库是空的——没有卡号、没有应用绑定记录。这时候如果直接展示一个空白列表,用户会感到困惑。一个好的 App 应该在空状态时展示友好的引导信息,告诉用户「这里还没有内容,接下来你可以这样做」。这就是 EmptyState 组件的价值。

本篇涵盖:EmptyState @Builder 组件设计、Blank() 弹性布局实现垂直居中、多场景空状态(列表为空/搜索无结果/筛选无匹配/导入为空)、条件渲染展示空状态、引导按钮点击导航。


空状态引导页架构图

图1:EmptyState 组件结构 + Blank 弹性布局 + 多场景空状态 + 条件渲染


一、EmptyState 组件设计

1.1 组件结构

// 通用的空状态组件
@Builder
private EmptyState(icon: string, title: string,
                   desc: string, btnText: string, btnAction: () => void) {
  Column() {
    // ① 大图标(Emoji / 自定义图标)
    Text(icon)
      .fontSize(48)
      .margin({ bottom: 16 })

    // ② 标题(主要说明)
    Text(title)
      .fontSize(18)
      .fontWeight(AppFonts.WEIGHT_BOLD)
      .fontColor(AppColors.TEXT)
      .margin({ bottom: 8 })

    // ③ 描述文案(详细说明)
    Text(desc)
      .fontSize(12)
      .fontColor(AppColors.TEXT_2)
      .textAlign(TextAlign.Center)
      .margin({ bottom: 20 })

    // ④ 引导按钮(操作入口)
    Button(btnText, { type: ButtonType.Normal })
      .fontSize(12)
      .fontColor('#FFFFFF')
      .backgroundColor(AppColors.PRIMARY)
      .borderRadius(18)
      .height(36)
      .width(140)
      .onClick(() => btnAction())
  }
  .alignItems(HorizontalAlign.Center)
  .width('100%')
}

1.2 组件层级

层级 组件 说明
Text(icon) 大号 Emoji 图标,视觉吸引注意
Text(title) 核心状态说明,粗体醒目
Text(desc) 辅助引导文案
Button(btnText) CTA 按钮,点击后引导用户操作

二、Blank() 弹性布局实现垂直居中

2.1 为什么需要 Blank

空状态页面需要在屏幕中间展示,但页面上方有 TitleBar、下方有 TabBar。直接设置 justifyContent(FlexAlign.Center) 会让内容整体居中,但如果内容偏少可能会偏上或偏下。使用 Blank() 可以弹性撑开,将 EmptyState 推到视觉中心。

// 空状态页面结构
Column() {
  // ① 标题栏(固定高度)
  TitleBar()

  // ② 弹性撑开区域
  Blank()

  // ③ 空状态内容(居中显示)
  this.EmptyState('📭', '暂无绑定记录',
    '你还没有添加任何应用绑定\n点击下方按钮开始添加',
    '+ 添加应用', () => this.navigateToAddPage())

  // ④ 弹性撑开区域
  Blank()

  // ⑤ 底部 TabBar(固定高度)
  TabBar()
}
.height('100%')

2.2 Blank() 的弹性原理

Blank() 是一个不可见的弹性组件,会自动占据 Column 中的剩余空间。两个 Blank() 会把中间的 EmptyState 推到 Column 的垂直中心。

对比 实现方式 效果
justifyContent: Center 只居中子元素 内容可能偏上(TabBar 占位)
Blank() 双边撑开 上下 Balance 严格视觉居中

2.3 结合三态 UI

// 在实际页面中,空状态是三态 UI 的"正常内容"的一部分
if (this.loading) {
  this.LoadingState()
} else if (this.loadError) {
  this.ErrorState(this.loadError)
} else if (this.rows.length === 0) {
  this.EmptyStatePage()      // ← 这里使用 Blank + EmptyState
} else {
  this.ContentPage()         // ← 正常列表
}

三、多场景空状态

不同的场景需要不同的空状态文案和图标:

3.1 场景定义

// 各个页面调用 EmptyState 的场景

// 首页 — 没有绑定记录
this.EmptyState('📭', '暂无绑定记录',
  '你还没有添加任何应用绑定\n点击下方按钮开始添加',
  '+ 添加应用', () => { this.navigate('pages/AddAppPage') })

// 卡号管理 — 没有卡号
this.EmptyState('💳', '暂无卡号',
  '点击右上角「+」添加你的第一张卡号',
  '', () => {})   // 不需要按钮,右上角有 +

// 搜索页 — 搜索无结果
this.EmptyState('🔍', '未找到匹配结果',
  '尝试修改搜索关键词或筛选条件',
  '', () => {})

// 粘贴导入 — 未识别到应用
this.EmptyState('📎', '未识别到应用信息',
  '请确认粘贴内容包含应用名称和卡号',
  '重新粘贴', () => { this.pastedText = '' })

3.2 场景矩阵

场景 图标 标题 引导操作
绑定记录为空 📭 暂无绑定记录 + 添加应用
卡号列表为空 💳 暂无卡号 右上角 +
搜索无结果 🔍 未找到匹配结果 无(仅在搜索框输入)
粘贴导入为空 📎 未识别到应用信息 重新粘贴
筛选无匹配 当前筛选无结果 重置筛选

四、引导按钮导航

4.1 导航封装

// 页面内部的导航方法
private navigateToAddPage(): void {
  router.pushUrl({
    url: 'pages/AddAppPage',
    params: {} as Record<string, Object>
  })
}

4.2 关闭弹窗后导航

有时候空状态出现在弹窗或面板中,需要先关闭再导航:

private handleAction(): void {
  if (this.isInSheet) {
    this.showSheet = false    // 先关闭面板
  }
  // 延迟导航,给关闭动画留时间
  setTimeout(() => {
    this.navigateToAddPage()
  }, 300)
}

五、本篇小结

知识点 核心要点
EmptyState @Builder 参数化:icon/title/desc/btnText/btnAction
Blank() 弹性布局 两个 Blank() 将内容推到垂直居中
多场景复用 搜索/列表/导入/筛选各自定制文案
条件渲染 if/else 判断数据长度为 0 时展示空状态
引导按钮 点击导航到添加页面,考虑弹窗延迟

参考资料

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

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

更多推荐