news 2026/9/4 16:48:48

鸿蒙原生应用实战:用 ArkUI 搭志愿服务首页 —— 沉浸式 HeroCard 与项目推荐

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙原生应用实战:用 ArkUI 搭志愿服务首页 —— 沉浸式 HeroCard 与项目推荐

鸿蒙原生应用实战:用 ArkUI 搭志愿服务首页 —— 沉浸式 HeroCard 与项目推荐

App 17「志愿服务」首页(HomeTab),主题色#EF4444红色,4 个 Tab 分别为首页(🤝)、活动(📋)、记录(🏅)、我的(👤)。首页采用沉浸式渐变 HeroCard(智能管理 + 3 栏统计)+ 快捷功能入口 + 本周数据可点击条形图 + 横向分类筛选 + 推荐项目列表(含进度条与 HOT/NEW/精选 标签)。本篇基于17-volunteer/entry/src/main/ets/pages/HomeTab.ets(约 193 行)逐段拆解,附 4 张实机截图。

一、整体结构:5 个 @Builder 的内容流

HomeTab 的结构与 App 13/14/15/16 高度同源——都是 5 个 @Builder 块拼出"信息流首页":

build() { Column() { Scroll() { Column({ space: 14 }) { this.HeroCard() this.QuickActionRow() this.WeekChartCard() this.CategoryBar() this.ItemList() Blank().height(this.safeBottom + 20) } .width('100%').padding({ left: D.pad, right: D.pad }) } .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top) } .width('100%').height('100%').backgroundColor(C.bg) }

5 个块按"头部 → 工具 → 数据 → 筛选 → 列表"五段叙事

  1. HeroCard— 红色渐变欢迎 + 3 栏统计
  2. QuickActionRow— 4 个圆形入口(搜索/收藏/统计/消息)
  3. WeekChartCard— 本周数据可点击条形图
  4. CategoryBar— 横向分类筛选(全部/推荐/热门/最新)
  5. ItemList— 3 条推荐项目(含进度条与标签)

"沉浸式顶部"设计:HeroCard 的padding({ top: this.safeTop + 20 })让红色渐变延伸到状态栏背后,形成"顶部品牌色块"——这是本系列一直沿用的沉浸式模式。

Blank().height(this.safeBottom + 20)底部留白:让最后一条卡片不贴到 Tab 栏,加 20vp 视觉缓冲。

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

二、HeroCard:红色渐变 + 智能管理 + 3 栏统计

HeroCard 是顶部品牌区——红色(C.primary)渐变到浅红(C.accent)形成"热情公益"的视觉调性:

@Builder HeroCard() { Column({ space: 12 }) { Row({ space: 12 }) { Text('🏠').fontSize(24) Column({ space: 4 }) { Text('智能管理').fontSize(20).fontWeight(FontWeight.Bold).fontColor('#FFFFFF') Text('高效便捷 · 智能推荐').fontSize(12).fontColor('rgba(255,255,255,0.85)') }.alignItems(HorizontalAlign.Start).layoutWeight(1) }.width('100%') Row() { ForEach(this.stats, (s: StatItem, idx: number) => { Column({ space: 2 }) { Text(s.value).fontSize(20).fontWeight(FontWeight.Bold).fontColor('#FFFFFF') Text(s.label).fontSize(10).fontColor('rgba(255,255,255,0.8)') }.alignItems(HorizontalAlign.Start).layoutWeight(1) if (idx < this.stats.length - 1) { Column().width(1).height(28).backgroundColor('rgba(255,255,255,0.25)') } }, (s: StatItem) => s.label) }.width('100%') } .width('100%').padding(18).padding({ top: this.safeTop + 20 }) .borderRadius({ bottomLeft: D.rLg, bottomRight: D.rLg }) .linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] }) }

两个 padding 写法

.width('100%').padding(18).padding({ top: this.safeTop + 20 })

padding(18).padding({ top: this.safeTop + 20 })是 ArkUI 里"叠加 padding"的写法——先给四面 18vp,再单独把顶部覆盖为safeTop + 20。这样左右下三边距统一为 18,顶部则跟随状态栏高度自适应。比padding({ top: safeTop+20, left: 18, right: 18, bottom: 18 })这种"四值全写"简洁。

borderRadius({ bottomLeft: D.rLg, bottomRight: D.rLg })只圆角底部:让顶部与状态栏无缝拼接(沉浸式),底部则形成大圆角与下方白色卡片做软分隔。"上不留白、下大圆角"是沉浸式 HeroCard 的标准做法

3 栏统计128 / 32 / 86%对应"总数 / 今日 / 完成率"——"量 → 速 → 质"三角

  • 总数 128——累计活动总量
  • 今日 32——当日新增
  • 完成率 86%——完成质量

rgba(255,255,255,0.25)25% 不透明白色作为分隔竖线,在红色背景上柔和不刺眼。if (idx < this.stats.length - 1)防止最后一条也加分隔线。

HeroCard 与 App 13 同源:都是"图标 + 标题 + 副标题 + 3 栏统计 + 135° 渐变"——同一套模板,换主题色(紫→红)+ 换标题文案(音乐歌单→智能管理)

三、QuickActionRow:4 个圆形入口

QuickActionRow 是 4 个常用功能(搜索/收藏/统计/消息)的快捷入口:

@Builder QuickActionRow() { Row() { ForEach(this.actions, (item: QuickAction) => { Column({ space: 6 }) { Row() { Text(item.icon).fontSize(22) } .width(44).height(44).backgroundColor(C.cardSoft).borderRadius(D.rSm).justifyContent(FlexAlign.Center) Text(item.title).fontSize(10).fontColor(C.textSub) } .layoutWeight(1) .onClick(() => { promptAction.showToast({ message: item.title }); }) }, (item: QuickAction) => item.title) } .width('100%').padding(12).backgroundColor(C.card).borderRadius(D.rMd) .border({ width: 1, color: C.stroke }).justifyContent(FlexAlign.SpaceAround) }

44×44 圆角图标块borderRadius(D.rSm)10vp 圆角,非正圆)+ 下方 10sp 文字。justifyContent(FlexAlign.SpaceAround)让 4 个入口之间留出等距空白。promptAction.showToast({ message: item.title })是"轻反馈"——点击立刻弹"搜索""收藏"等文字,给用户"我收到了点击"的反馈。

与 App 13 几乎完全同源——只有actions数组的内容略不同(App 13 是 4 个 app 内功能,App 17 是"搜索/收藏/统计/消息")。同一套"圆形图标+文字"骨架换数据

四、WeekChartCard:可点击的 7 天条形图

WeekChartCard 是 7 天数据条形图,点击柱子切换高亮(与 App 13 相同的"可交互周图"):

@Builder WeekChartCard() { Column({ space: 12 }) { Row() { Text('📊 本周数据').fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text) Blank() Text('30 次').fontSize(13).fontWeight(FontWeight.Bold).fontColor(C.primary) }.width('100%') Row({ space: 4 }) { ForEach(this.weekBars, (b: WeekBar, idx: number) => { Column({ space: 6 }) { Column() .width(18) .height(Math.max(6, b.value / 7 * 80)) .borderRadius(4) .linearGradient({ angle: 180, colors: idx === this.selectedBar ? [[C.primary, 0.0], [C.accent, 1.0]] : [[C.primarySoft, 0.0], [C.primary, 1.0]] }) Text(b.day).fontSize(10) .fontColor(idx === this.selectedBar ? C.primary : C.textDim) .fontWeight(idx === this.selectedBar ? FontWeight.Bold : FontWeight.Normal) }.layoutWeight(1).alignItems(HorizontalAlign.Center) .onClick(() => { this.selectedBar = idx; }) }, (b: WeekBar) => b.day) }.width('100%') } .width('100%').padding(14).backgroundColor(C.card).borderRadius(D.rMd) .border({ width: 1, color: C.stroke }) }

柱子高度 =b.value / 7 * 80:把 value 归一化到 80vp 上限。Math.max(6, ...)兜底最低 6vp 防止柱子消失。选中柱子用主色渐变(红→浅红),未选用浅红→红(逆向)——视觉上"激活"更亮。

@State selectedBar: number = 4初始选中"五"(idx=4,value=4)——**"周五数据刚好居中"**是 demo 的默认值巧思(既能演示选中态,又不显眼)。

点击this.selectedBar = idx;切换高亮——@State一变,整张卡的渐变色和文字重渲染。"点击即反馈"的响应式范式

30 次汇总:3+5+2+6+4+7+3 = 30——"汇总 = 各柱之和"完全成立(App 13 同样是 30 次 = 3+5+2+6+4+7+3 也成立,App 15/16 有口径不一致的坑,App 17 与 App 13 一样严格自洽)。

"30 次"的语义是"本周完成 30 次志愿活动"——"次数"是志愿服务的核心量化指标(比"时长"更直观)。"30 次"= 每位志愿者每天 4-5 次活动是合理的活跃水平。

五、CategoryBar:横向分类筛选

CategoryBar 是 4 个分类(全部/推荐/热门/最新)的胶囊标签,横滑滚动

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

选中态三件套(背景/文字/边框)——同系列标准做法:

  • 选中:主色背景(红)+ 白字 + 主色描边
  • 未选:白底 + 灰字 + 浅灰描边

Scroll包裹让 4 个分类可横滑(4 个装得下,但 Scroll 让未来加分类不会破版)。"分类条 + 横滑"是移动端"分类筛选"的标准组件

onClick(() => { this.activeCat = idx; })切换状态——demo 没有联动 ItemList 过滤(与 App 13 一样是"假筛选"),但状态机已就绪,真实项目只需加filteredItems()即可联动。

六、ItemList:3 条推荐项目(含标签+进度条)

ItemList 是首页的"内容主体"——3 条推荐项目,每条都是"emoji + 标题 + 标签 + 描述 + 进度条":

@Builder ItemList() { Column({ space: 10 }) { Row() { Text('推荐列表').fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text) Blank() Text('查看全部 ›').fontSize(11).fontColor(C.primary) }.width('100%') ForEach(this.items, (item: ListItem) => { Column({ space: 10 }) { Row({ space: 12 }) { Row() { Text(item.emoji).fontSize(28) } .width(56).height(56).backgroundColor(C.cardSoft).borderRadius(D.rMd).justifyContent(FlexAlign.Center) Column({ space: 4 }) { Row() { Text(item.title).fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text).layoutWeight(1) Text(item.tag).fontSize(9).fontColor('#FFFFFF') .backgroundColor(item.tag === 'HOT' ? C.danger : item.tag === 'NEW' ? C.ok : C.accent) .padding({ left: 5, right: 5, top: 2, bottom: 2 }).borderRadius(D.rSm) }.width('100%') Text(item.desc).fontSize(12).fontColor(C.textDim) }.alignItems(HorizontalAlign.Start).layoutWeight(1) }.width('100%') Row() { Text('进度').fontSize(10).fontColor(C.textDim) Stack({ alignContent: Alignment.Start }) { Column().width('100%').height(5).backgroundColor(C.cardSoft).borderRadius(3) Column().width(`${item.progress}%`).height(5).borderRadius(3).backgroundColor(C.primary) }.layoutWeight(1).margin({ left: 8, right: 8 }) Text(`${item.progress}%`).fontSize(10).fontColor(C.primary).fontWeight(FontWeight.Bold) }.width('100%') } .width('100%').padding(12).backgroundColor(C.card).borderRadius(D.rMd) .border({ width: 1, color: C.stroke }) .onClick(() => { promptAction.showToast({ message: item.title }); }) }, (item: ListItem) => item.id.toString()) }.width('100%') }

6.1 三种标签的语义色彩

item.tag === 'HOT' ? C.danger : item.tag === 'NEW' ? C.ok : C.accent是关键三元表达式:

  • HOTC.danger深红(#FF5A6E)——最显眼的"热门"标签
  • NEWC.ok绿色(#2BB673)——清新"新"标签
  • 精选C.accent浅红(#F87171)——品牌色"精选"标签

3 色映射对应 3 种语义——"HOT"是紧迫感(红色警报)、"NEW"是新鲜感(绿色生命)、"精选"是品牌质感(主题浅色)。**"标签色 = 标签语义"**是良好的视觉设计。

3 条项目:📦 热门项目一 HOT(已参与 128 人,进度 75%)/ 🎯 推荐项目二 NEW(86 人,45%)/ ⭐ 精选项目三 精选(256 人,90%)——3 种标签都有数据展示

6.2 Stack 进度条(双通道)

Row() { Text('进度').fontSize(10).fontColor(C.textDim) Stack({ alignContent: Alignment.Start }) { Column().width('100%').height(5).backgroundColor(C.cardSoft).borderRadius(3) Column().width(`${item.progress}%`).height(5).borderRadius(3).backgroundColor(C.primary) }.layoutWeight(1).margin({ left: 8, right: 8 }) Text(`${item.progress}%`).fontSize(10).fontColor(C.primary).fontWeight(FontWeight.Bold) }

"Stack 进度条 = 背景条 + 前景条叠加"——Stack({ alignContent: Alignment.Start })让前景对齐到左边起点,背景 100% 宽、前景${item.progress}%宽。width用模板字符串拼接百分比,item.progress既是宽度数字又是右侧文字一处数据两处联动

"进度"标签 + 进度条 + 百分比文字"——三处同步表达"完成度":

  • "进度" 文字(10sp 灰)
  • 进度条(5vp 高主色圆角)
  • "75%" 数字(10sp 主色加粗)

色弱用户不靠颜色就能读(靠"进度"和"75%"两处文字)——"颜色 + 文字双通道"原则

"项目 128/86/256 人参与"的数字故事:项目三(精选 256 人 + 90% 完成度)参与最多且进度最远——**"参与人数与完成进度正相关"**符合大众心理(好项目越多人参与、参与越多越容易完成)。三个数据互相印证,首页"数据自洽"。

七、内容流首页的"节奏感"设计

App 17 首页 5 块内容从上到下有明确的"节奏感"——

第 1 块 HeroCard(红色渐变):视觉冲击最强(红色 135° 渐变),承担"品牌印象"。用户在首页第 1 秒看到这块——决定"这个 App 是做什么的"。

第 2 块 QuickActionRow(4 入口):中度视觉(白色卡片 + 圆角图标),承担"工具导航"。节奏从"冲击"过渡到"实用"

第 3 块 WeekChartCard(条形图):中度视觉(白色卡片 + 数据图),承担"行为数据"。节奏从"导航"过渡到"数据"

第 4 块 CategoryBar(横向分类):轻度视觉(小胶囊标签),承担"分类筛选"。节奏从"数据"过渡到"选择"——视觉重量递减,给用户"选择更多"的心理暗示。

第 5 块 ItemList(推荐项目):中重视觉(白卡 + 大色块 + 进度条 + 标签),承担"主内容"。节奏从"选择"过渡到"消费"——这是用户最终要消费的内容

"节奏感" = 视觉重量的"强 → 中 → 中 → 轻 → 中"的起伏——不是"统一重量从头到尾"(会显得平铺直叙),也不是"忽强忽弱"(会显得杂乱)。"先冲击后实用"是设计节奏的黄金法则

对比 App 14 首页

  • App 14:HeroCard(活动)→ QuickActionRow(4 运动)→ WeeklyChart(数据)→ SectionTitle + VenueList(5 场地)→ SectionTitle + RankList(3 排行)
  • App 17:HeroCard(活动)→ QuickActionRow(4 入口)→ WeekChartCard(数据)→ CategoryBar(分类)→ ItemList(3 项目)

两者结构完全同源——"5 块节奏"是系列化首页的通用骨架

八、@State 的克制 + 主题色的力量

HomeTab 只有2 个 @StateactiveCat(分类选中)+selectedBar(柱子高亮)。其他数据全部private不可变——"会变的只有交互态"是 ArkUI 健康状态管理的铁律

主题色#EF4444红色的语义:红色在中国文化里"热情、公益、爱心",是志愿服务的经典色(红十字会、志愿者红马甲)。相比 App 14 绿(运动活力)和 App 15 绿(环保),App 17 的红更"情感"——"颜色即产品调性"

与 App 13 紫色对比:App 13 紫 #8B5CF6(音乐、浪漫、二次元),App 17 红 #EF4444(志愿、热情、公益)——"同一套代码框架换主题色 + 换文案 = 完全不同的产品"。这是系列化 demo 最重要的方法论:模板复用、主题演化

九、总结

App 17 首页解析完毕。沉浸式红色 HeroCard + 可点击周图 + 横向分类 + 标签+进度条项目卡是四大亮点,配合红色志愿服务调性与 App 13 的"主题复刻"展示了一个重要方法论:同一套 UI 框架,换主题色 + 换文案 + 换数据 = 完全不同的产品。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/4 16:48:05

【2014-08-28】Lua快速学习笔记:函数

[历史归档] 本文原发布于 cstriker1407.info 个人博客&#xff0c;内容为历史存档&#xff0c;仅供参考。 发布时间&#xff1a; 2014-08-28 &#xff5c; 标题&#xff1a;Lua快速学习笔记&#xff1a;函数 &#xff5c; 分类&#xff1a; 编程 / C && C / Lua &…

作者头像 李华
网站建设 2026/9/4 16:45:33

Windows DLL 缺失、运行库报错怎么办?电脑修复工具大全及解决方法

Windows DLL 缺失、运行库报错怎么办&#xff1f;电脑修复工具大全及解决方法 平时使用 Windows 电脑&#xff0c;尤其是运行游戏、开发工具或者一些老软件时&#xff0c;经常会遇到各种运行库问题。 比如&#xff1a; 找不到 xxx.dll 文件xxx.dll 丢失xxx.dll 无法运行程序无…

作者头像 李华
网站建设 2026/9/4 16:44:14

MATLAB实现AGV多机协同调度的QLearning仿真系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/4 16:43:01

右豹邀请码8831:注册前先核对官方入口

右豹邀请码8831&#xff1a;注册前先核对官方入口 右豹是深圳不鸣文化科技有限公司旗下的内容创作与推广服务平台。公开页面介绍&#xff0c;平台面向创作者与品牌方提供内容推广、项目规则、工具与学习服务等信息&#xff1b;具体可参与的项目、素材要求、结算规则和参与条件&…

作者头像 李华