鸿蒙原生应用 ArkUI 实战:渐变汇总卡 + 票据列表 —— 电子票据首页的总账架构

App 52「电子票据管理」首页(HomeTab),主题色 #0066CC 科技蓝,4 个 Tab 分别为首页(🧾)、上传(📤)、分类(📂)、我的(👤)。本篇基于 52-e-receipt/entry/src/main/ets/pages/HomeTab.ets(共 102 行)逐段拆解,附 4 张实机截图。

首页整体布局

一、整体结构:三区"Header + 汇总卡 + 列表"布局

首页是"品牌头部 + 金额汇总 + 票据列表"的三区布局——3 个 @Builder 块:

build() {
  Column() {
    this.Header()
    Scroll() {
      Column({ space: 14 }) {
        this.SummaryCard()
        this.SectionTitle('最近票据')
        this.ReceiptList()
      }
      .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 块结构:Header(单行品牌头)→ SummaryCard(蓝色渐变金额汇总卡)→ ReceiptList(4 条票据卡片列表)。首页是"票据总览页"——先亮出本月票据金额(1010 元)、票据数(28 张)、可报销(856 元)三大核心数据,再列出最近 4 条票据明细。

二、Header:单行品牌头

Header() {
  Column() {
    Text('票据管理').fontSize(22).fontWeight(FontWeight.Bold).fontColor(C.text)
      .width('100%').padding({ top: this.safeTop + 10, left: D.pad, right: D.pad, bottom: 12 })
  }.width('100%').backgroundColor(C.card)
}

22 号加粗、safeTop + 10 避让状态栏、白底全宽。与系列工具型首页(App 45/App 47/App 51)同款单行标题范式。

三、SummaryCard:蓝色渐变金额汇总卡

SummaryCard() {
  Column({ space: 16 }) {
    Column({ space: 6 }) {
      Text('本月票据总额(元)').fontSize(13).fontColor('#FFFFFF').opacity(0.9)
      Text('1,010.00').fontSize(32).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
    }.alignItems(HorizontalAlign.Start).width('100%')
    Row() {
      Column({ space: 4 }) {
        Text('票据数').fontSize(12).fontColor('#FFFFFF').opacity(0.9)
        Text('28 张').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
      }.alignItems(HorizontalAlign.Start).layoutWeight(1)
      Column({ space: 4 }) {
        Text('可报销').fontSize(12).fontColor('#FFFFFF').opacity(0.9)
        Text('¥856').fontSize(16).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
      }.alignItems(HorizontalAlign.Start).layoutWeight(1)
    }.width('100%')
  }
  .width('100%').padding(20).borderRadius(D.rLg)
  .linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })
}

逐点拆解:

  1. 蓝色渐变:linearGradient 从 #0066CC 科技蓝渐变到 #4D99E0 亮蓝——蓝色传达"专业财务管理"气质。
  2. 主金额 32 号加粗:"1,010.00" 是全卡最大字号——月度票据总额是首页最核心的数字(用户打开 App 第一眼要看"这个月花了多少钱")。
  3. 两列副统计:layoutWeight(1) 均分——票据数 28 张(数量)+ 可报销 ¥856(金额),一虚一实组合,"可报销"是财务场景的核心诉求。
  4. 白字层级:13 号标签 opacity(0.9) 弱化、16 号数值 1.0 强调——"标签轻、数值重"的层级。

四、Receipt 数据模型 + SectionTitle

interface Receipt {
  id: number;
  emoji: string;
  title: string;
  amount: number;
  category: string;
  date: string;
}
private receipts: Receipt[] = [
  { id: 1, emoji: '🍽️', title: '餐饮发票', amount: 288, category: '餐饮', date: '08-14' },
  { id: 2, emoji: '🚕', title: '打车电子发票', amount: 46, category: '交通', date: '08-13' },
  { id: 3, emoji: '🏨', title: '酒店住宿发票', amount: 520, category: '住宿', date: '08-12' },
  { id: 4, emoji: '🛒', title: '超市购物小票', amount: 156, category: '购物', date: '08-11' }
];

Receipt 六字段:emoji(类型图标)、title(名称)、amount(金额)、category(分类)、date(日期)。4 条票据日期递减(08-14→08-11),按时间倒序排列。

SectionTitle(title: string) {
  Row() {
    Text(title).fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text)
    Blank()
    Text('全部 >').fontSize(12).fontColor(C.textDim)
  }.width('100%')
}

Blank() 撑开中间空间——左侧标题 + 右侧"全部 >"入口,Blank 是弹性占位的典型用法。

五、ReceiptList:最近票据卡片列表

ReceiptList() {
  Column({ space: 10 }) {
    ForEach(this.receipts, (r: Receipt) => {
      Row({ space: 12 }) {
        Row() { Text(r.emoji).fontSize(22) }
        .width(44).height(44).backgroundColor(C.primarySoft).borderRadius(D.rSm).justifyContent(FlexAlign.Center)
        Column({ space: 3 }) {
          Text(r.title).fontSize(14).fontColor(C.text)
          Text(r.category + ' · ' + r.date).fontSize(12).fontColor(C.textDim)
        }.alignItems(HorizontalAlign.Start).layoutWeight(1)
        Text('¥' + r.amount).fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text)
      }
      .width('100%').padding(12).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke })
      .onClick(() => { promptAction.showToast({ message: r.title }); })
    }, (r: Receipt) => r.id.toString())
  }.width('100%')
}

逐点拆解:

  1. 44×44 主色软底图标块:C.primarySoft(#E1ECFD)淡蓝圆角底 + 22 号 emoji——每张票据一个专属 emoji(🍽️🚕🏨🛒),视觉快速识别票据类型。
  2. 标题 + 副信息:14 号标题 + 12 号"餐饮 · 08-14"(分类 · 日期拼接)——layoutWeight(1) 撑开中间区。
  3. 右对齐金额:15 号 Bold ¥288——金额右对齐(财务列表惯例:数字靠右便于横向比对)。
  4. 整卡点击:onClick 弹 Toast 票据名——产品化后跳票据详情页。

首页列表与交互

六、数据自洽:汇总 = 明细之和

      Text('1,010.00').fontSize(32).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
  { id: 1, emoji: '🍽️', title: '餐饮发票', amount: 288, category: '餐饮', date: '08-14' },
  { id: 2, emoji: '🚕', title: '打车电子发票', amount: 46, category: '交通', date: '08-13' },
  { id: 3, emoji: '🏨', title: '酒店住宿发票', amount: 520, category: '住宿', date: '08-12' },
  { id: 4, emoji: '🛒', title: '超市购物小票', amount: 156, category: '购物', date: '08-11' }

汇总卡 1010 元 = 4 条明细之和(288 + 46 + 520 + 156 = 1010)——汇总 = 明细之和,演示数据自洽。产品化时汇总应由明细动态求和(reduce),而非硬编码。

点击票据卡片弹出提示

七、科技蓝主题的视觉策略

export class C {
  static readonly bg: string = '#F2F5FB';
  static readonly card: string = '#FFFFFF';
  static readonly cardSoft: string = '#F4F6FB';
  static readonly stroke: string = '#EAEEF6';
  static readonly text: string = '#1C2333';
  static readonly textSub: string = '#5A6483';
  static readonly textDim: string = '#9AA3BC';
  static readonly primary: string = '#0066CC';
  static readonly primarySoft: string = '#E1ECFD';
  static readonly accent: string = '#4D99E0';
  static readonly warn: string = '#FF9F1C';
  static readonly danger: string = '#FF5A6E';
  static readonly ok: string = '#2BB673';
}

逐点拆解:

  1. primary = #0066CC:科技蓝传达"专业/效率/财务管理"气质——与 App 46 通讯录蓝(#0984E3 亮蓝)同色系但更深沉(#0066CC 更正式)。
  2. accent = #4D99E0:亮蓝渐变终点——蓝系渐变是"财务工具"的视觉标识。
  3. primarySoft = #E1ECFD:淡蓝用于图标块底色——主色的浅色变体,保持蓝系一致性。

八、系列横向对比:蓝系工具首页三剑客

工具首页代表 App首页焦点核心动作主题色
金额汇总App 52 票据渐变汇总卡 + 票据列表看总额 → 查明细#0066CC 科技蓝
通讯录App 46 通讯录在线状态 + 成员列表联系人#0984E3 亮蓝
账务余额App 47 班费余额卡 + 收支动态看账#00A862 翡翠绿

差异点:App 52 的"可报销 ¥856"是财务专属维度(报销是票据场景独有,其他工具没有)——汇总卡的"总额 + 张数 + 可报销"三列组合是票据管理的特有数据模型。

滚动后查看最近票据明细

九、开发者视角:调试与验证技巧

  1. 金额格式化:Text('¥' + r.amount) 直接拼字符串——amount 是 number(288),拼接自动转字符串。产品化时应统一 toFixed(2) 保留两位小数(288.00),否则与汇总卡的"1,010.00"格式不一致。
  2. 嵌套圆角:图标块 borderRadius(10) 小于卡片 borderRadius(14)——嵌套层级圆角递减(内层小、外层大),视觉上"图标嵌在卡片里"的层次感。
  3. 汇总 = 明细和:1010 元 = 288+46+520+156——演示数据务必自洽(否则验收对不上账)。真实产品中汇总卡应由明细动态求和。
  4. SectionTitle 的 Blank:Blank() 撑开"最近票据"与"全部 >"——验证 Blank 的弹性占位在窄屏上不挤压两侧文字。

十、演进方向

方向当前状态产品化演进
汇总动态化硬编码 1010 元receipts.reduce() 动态求和
票据详情Toast"餐饮发票"跳票据详情页(含原图/字段/报销状态)
报销一体化"可报销 ¥856" 展示对接企业报销系统,一键生成报销单
消费洞察列表按时间倒序月度趋势对比 + 单笔异常提醒
票据安全无云端备份 + 到期提醒

十一、一句话总结

首页以"渐变汇总卡 + 票据列表"完成了电子票据的总账展示。linearGradient 科技蓝渐变汇总卡(32 号主金额 + 两列副统计)、44×44 淡蓝底 emoji 图标块、layoutWeight(1) 三栏列表行(图标+标题+金额)、Blank() 弹性占位 SectionTitle——102 行代码,一个"看总额 → 查明细 → 去报销"的票据总览页,也是财务工具型首页的标准范式。

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

Logo

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

更多推荐