鸿蒙应用开发实战【58】— 状态列表页StatusListPage开发

鸿蒙应用开发实战【58】--- 状态列表页StatusListPage开发

本文是「号码助手全栈开发系列」第 58 篇,持续更新中...

开源社区:https://openharmonycrossplatform.csdn.net


前言

StatusListPage 是按状态筛选的应用列表页,用户从首页的统计卡片点击进入(如"待换绑"),查看该状态下所有应用,并支持分类/卡号 chip 二次筛选。

本篇涵盖:路由接收 status 参数、按状态查询 listByStatus、Chip 筛选行(分类+卡号)、水平滚动 chips、空状态(无待处理事项)、getFilteredRows 二次过滤、与首页 onPageShow 联动。


一、页面结构

复制代码
┌──────────────────────┐
│  ‹   待换绑 · 3       │
├──────────────────────┤
│                      │
│  [全部][APP][网站]    │  ← 水平滚动 chips
│  [卡1][卡2]          │
│                      │
│  ┌──┐ 微信           │
│  │W │ APP   卡1      │
│  └──┘ 待换绑         │
│                      │
│  ┌──┐ 淘宝           │
│  │T │ APP   卡2      │
│  └──┘ 待换绑         │
└──────────────────────┘

二、路由参数

typescript 复制代码
aboutToAppear(): void {
  const params = this.getUIContext().getRouter().getParams() as Record<string, Object>
  if (params && typeof params['status'] === 'string') {
    this.statusLabel = params['status'] as string
  }
  this.loadData()
}

来自首页统计卡片的调用:

typescript 复制代码
// HomePage StatCard
.onClick(() => {
  this.navigate('pages/StatusListPage', { status: '待换绑' })
})

三、数据加载

typescript 复制代码
private async loadData(): Promise<void> {
  this.loading = true
  try {
    this.cards = await CardDao.listAll()
    const cardLabelMap = new Map<number, string>()
    for (const c of this.cards) {
      cardLabelMap.set(c.id ?? 0, c.label)
    }
    const bindings = await AppBindingDao.listByStatus(this.statusLabel as BindingStatus)
    this.rows = bindings.map(b => ({
      binding: b,
      cardLabel: cardLabelMap.get(b.card_id) ?? ''
    }))
  } finally {
    this.loading = false
  }
}

AppBindingDao.listByStatus:

typescript 复制代码
async listByStatus(status: BindingStatus): Promise<AppBindingEntity[]> {
  const predicates = new RdbPredicates('app_bindings')
  predicates.equalTo('status', status)
  predicates.orderByDesc('updated_at')
  // 查询 → 遍历 ResultSet → 返回 entities
}

四、Chip 筛选行

4.1 水平滚动

typescript 复制代码
Scroll() {
  Row({ space: 8 }) {
    // 分类 chips
    ForEach(['全部', 'APP', '网站', '小程序'], (cat, idx) => {
      Text(cat)
        .fontColor(this.chipCatIdx === idx ? '#FFFFFF' : AppColors.TEXT_2)
        .backgroundColor(this.chipCatIdx === idx ? AppColors.PRIMARY : AppColors.CARD_B)
        .linearGradient(this.chipCatIdx === idx
          ? { angle: 135, colors: [[AppColors.PRIMARY, 0], [AppColors.PRIMARY_2, 1]] }
          : { angle: 135, colors: [[AppColors.CARD_B, 0], [AppColors.CARD_B, 1]] })
        .onClick(() => this.chipCatIdx = idx)
    })

    // 卡号 chips
    ForEach(this.cards, (card, idx) => {
      Text(card.label)
        .fontColor(this.chipCardIdx === idx + 1 ? '#FFFFFF' : AppColors.TEXT_2)
        .backgroundColor(this.chipCardIdx === idx + 1 ? AppColors.PRIMARY : AppColors.CARD_B)
        .onClick(() => {
          this.chipCardIdx = this.chipCardIdx === idx + 1 ? 0 : idx + 1
        })
    })
  }
}
.scrollable(ScrollDirection.Horizontal)  // 水平滚动
.scrollBar(BarState.Off)                 // 隐藏滚动条

点击切换:再次点击已选中的 chip 可取消选择(恢复到 idx=0)。

4.2 二次过滤

typescript 复制代码
private getFilteredRows(): AppRow[] {
  const CATEGORIES = ['全部', 'APP', '网站', '小程序']
  return this.rows.filter(r => {
    const catOk = this.chipCatIdx === 0 || r.binding.category === CATEGORIES[this.chipCatIdx]
    const cardOk = this.chipCardIdx === 0 || r.cardLabel === this.cards[this.chipCardIdx - 1]?.label
    return catOk && cardOk
  })
}

Chip 维度 选项数组 idx=0 含义 点击切换行为
分类 '全部','APP','网站','小程序' 全部 chipCatIdx = idx
卡号 this.cards 动态 全部 chipCardIdx = 点击取消

五、空状态

当某状态没有应用时(所有待换绑的应用都已处理完),显示完成状态:

typescript 复制代码
Column() {
  Column() {
    Text('✓').fontSize(Size.font24).fontColor('#FFFFFF').fontWeight(800)
  }
  .width(Size.s88).height(Size.s88).borderRadius(Size.s44)
  .linearGradient({ angle: 135, colors: [[AppColors.PRIMARY, 0], [AppColors.PRIMARY_2, 1]] })
  .justifyContent(FlexAlign.Center).margin({ bottom: 20 })

  Text('太棒了,没有待处理事项')
    .fontSize(Size.font15).fontWeight(AppFonts.WEIGHT_BOLD).fontColor(AppColors.TEXT)

  Button('返回首页', { type: ButtonType.Normal })
    .onClick(() => this.getUIContext().getRouter().back())
}

小结

要点 说明
路由参数 from HomePage StatCard: status
按状态查询 listByStatus 过滤 + orderByDesc
Chip 行 水平 Scroll + 二次筛选
Chip 切换 再次点击取消选择
空状态 "太棒了"完成状态
onPageShow 从详情页返回后自动刷新

下一篇文章,我们开发备份页 BackupPage------数据导出、导入、备份文件管理。


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


相关资源:

相关推荐
l134062082352 小时前
鸿蒙应用开发实战【85】— 应用签名与正式HAP打包
华为·harmonyos·鸿蒙系统
爸爸6192 小时前
鸿蒙应用开发实战【06】— 应用入口与生命周期管理(EntryAbility 深度解析)
华为·harmonyos·鸿蒙系统
不羁的木木2 小时前
《HarmonyOS技术精讲-NearLink Kit(星闪服务)》第8篇:智能家居控制——手机控制智能灯实战
智能手机·智能家居·harmonyos
用户0934077735143 小时前
HarmonyOS WPS Open SDK 实践:用能力分层重构 OpenFileRequest
typescript·harmonyos
春卷同学4 小时前
HarmonyOS掌上记账APP开发实践第21篇:Tabs 底部导航 — 鸿蒙应用的标准导航范式
华为·harmonyos
子非鱼94274 小时前
03-Flutter 鸿蒙实战 03:登录注册与本地会话持久化
网络·flutter·华为·harmonyos
子非鱼94274 小时前
01-Flutter 鸿蒙实战 01:会说话的相册项目架构拆解
flutter·华为·harmonyos
不羁的木木4 小时前
《HarmonyOS技术精讲-NearLink Kit(星闪服务)》第10篇:多设备协同——构建星闪网络实现数据同步
网络·华为·harmonyos
春卷同学4 小时前
HarmonyOS掌上记账APP开发实践第29篇:条件渲染与 ForEach — 动态 UI 的构建策略
ui·华为·harmonyos