
鸿蒙原生应用实战从零实现 —— 纪念册相册页三列照片网格与虚线上传条App 44「校园纪念册」相册页Func1Tab主题色#A29BFE淡紫色lavender4 个 Tab 分别为首页、相册、留言、我的。相册页采用Header 上传条 照片网格三区布局——白色单行 Header班级相册20 号加粗虚线边框上传条 22 号图标 上传照片到相册淡紫文字 28×28 圆形白色按钮SectionTitle相册照片 (8) 3 列照片网格 毕业合影 / 教学楼前 / 食堂聚餐 / ⛺ 军训时光 / 文艺汇演 / 图书馆自习 / 运动会 / 毕业旅行每张含 38 号 emoji 正方块 标题单行省略。本篇基于44-memorial-book/entry/src/main/ets/pages/Func1Tab.ets共 90 行逐段拆解附 4 张实机截图。一、整体结构三区Header 上传条 照片网格布局相册页是品牌头部 上传入口 照片墙的三区布局——3 个 Builder 块build() { Column() { this.Header() Scroll() { Column({ space: 14 }) { this.UploadBtn() this.SectionTitle(相册照片 ( this.photos.length )) this.PhotoGrid() } .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— 单行品牌头班级相册UploadBtn— 虚线边框上传条照片的上传入口PhotoGrid— 相册照片 (8) 3 列 8 张照片网格相册页对应首页计科2022级毕业纪念的照片集班级相册——首页是册子目录本页是册子的照片墙。项目源码开源https://gitee.com/codenestFlow/HarmonyOSHub二、Header单行标题Header() { Row() { Text(班级相册).fontSize(20).fontWeight(FontWeight.Bold).fontColor(C.text) } .width(100%).height(this.safeTop 56).padding({ top: this.safeTop, left: D.pad, right: D.pad }) .backgroundColor(C.card).alignItems(VerticalAlign.Bottom) }单行 20 号加粗、safeTop 56高度、白底、底部对齐——系列二级页统一范式。班级相册明确本页是班级这个群体的照片墙而非个人相册呼应纪念册的集体属性。三、UploadBtn虚线上传条UploadBtn() { Row({ space: 10 }) { Text().fontSize(22) Text(上传照片到相册).fontSize(14).fontColor(C.primary).layoutWeight(1) Text().fontSize(20).fontColor(#FFFFFF) .width(28).height(28).textAlign(TextAlign.Center).backgroundColor(C.primary).borderRadius(14) } .width(100%).padding(14).backgroundColor(C.card).borderRadius(D.rLg) .border({ width: 1, color: C.primary, style: BorderStyle.Dashed }) .onClick(() { promptAction.showToast({ message: 上传照片 }); }) }技术拆解虚线边框border({ width: 1, color: C.primary, style: BorderStyle.Dashed })——虚线边框是上传/添加的通用视觉语言App 40 上传页的格同款暗示此处可添加比实线更有待填充的语义。三元素布局 图标动作语义 上传照片到相册淡紫文字layoutWeight(1)撑开 28×28 圆形白色按钮视觉焦点——左动作、中说明、右按钮一行完整表达上传。整条可点onClick挂整条点击弹上传照片Toast——产品化后调起相册选择器PhotoViewPicker。白底圆角与下方照片卡同底靠虚线边框区分上传区 vs 照片区。四、PhotoGrid3 列照片网格PhotoGrid() { Grid() { ForEach(this.photos, (p: Photo) { GridItem() { Column() { Row() { Text(p.emoji).fontSize(38) } .width(100%).aspectRatio(1).backgroundColor(C.primarySoft) .borderRadius({ topLeft: D.rSm, topRight: D.rSm }).justifyContent(FlexAlign.Center) Text(p.caption).fontSize(11).fontColor(C.textSub).maxLines(1) .textOverflow({ overflow: TextOverflow.Ellipsis }).width(100%).padding(6) } .width(100%).backgroundColor(C.card).borderRadius(D.rSm).border({ width: 1, color: C.stroke }) .onClick(() { promptAction.showToast({ message: p.caption }); }) } }, (p: Photo) p.id.toString()) }.columnsTemplate(1fr 1fr 1fr).columnsGap(10).rowsGap(10).width(100%) }8 张照片18-27 行 毕业合影 / 教学楼前 / 食堂聚餐 / ⛺ 军训时光 / 文艺汇演 / 图书馆自习 / 运动会 / 毕业旅行——8 张照片覆盖大学四年的完整回忆线毕业、日常、生活、军训⛺、活动、旅行。技术拆解Grid 三列网格columnsTemplate(1fr 1fr 1fr) 10 间距——三列正方形照片墙与 App 40 上传页九宫格同款三列但本页是 8 张静态展示无 格。正方照片块aspectRatio(1)让图片区等比正方形38 号 emoji 居中、primarySoft淡紫底、只圆上两角下缘与标题相接。标题行11 号浅灰毕业合影等maxLines(1) Ellipsis 单行省略图书馆自习等四字标题无碍长标题防溢出padding(6)紧凑。整卡点击点击 Toast 照片标题产品化后全屏预览照片。keyp.id.toString()稳定唯一。8 张 vs 3×3 九格的空缺8 张照片在 3 列网格下排成332三行第三行右格空缺——这是照片数不定的自然布局Grid 自动处理若补齐到 9 张则完美 3×3Demo 的 8 张保留了继续上传的暗示配合顶部虚线上传条。五、跨页数据自洽相册页是纪念册的内容层相册页与首页、我的页的联动相册页班级相册↔ 首页计科2022级毕业纪念 班级毕业相册——本页即该纪念册的照片集。SectionTitle相册照片 (8)↔ 首页 256 张——8 是当前展示的照片数样例、256 是纪念册总照片数口径分层展示 vs 总量。上传照片↔ 首页 Banner邀请同学一起添加照片——上传动作是纪念册协作的一部分上传后相册照片 (N)与首页照片数同步 1。我的页86 我的照片↔ 相册页照片——86 是个人累计上传的照片数跨多本纪念册相册页展示的是当前纪念册的照片。六、实机截图与交互演示本节结合 4 张实机截图逐张还原相册页的视觉效果与交互过程。1. 相册页首屏上传条 照片网格第一张截图是相册页默认首屏顶部班级相册标题下方虚线边框上传条—— 图标 上传照片到相册 圆形白色按钮相册照片 (8)标题下是 3 列照片网格的前两行—— 毕业合影、 教学楼前、 食堂聚餐、⛺ 军训时光、 文艺汇演、 图书馆自习六张淡紫正方照片块排列整齐。2. 点击上传条上传照片 Toast第二张截图是点击虚线上传条后的反馈弹出上传照片Toast。整条可点图标/文字/加号任意区域虚线边框的可添加语义与点击反馈一致——产品化后此处调起相册选择器PhotoViewPicker选择真实照片。3. 点击照片弹出标题 Toast第三张截图是点击第一张照片 毕业合影后的反馈弹出毕业合影Toast。每张照片独立挂载onClick且闭包捕获各自的p.caption点击哪张就弹出哪个标题——照片网格点击参数传递正确产品化后此处全屏预览照片。4. 相册页完整视图八照片全览第四张截图是相册页的完整视图8 张照片全部可见——第三行是 运动会、 毕业旅行右格空缺暗示可继续上传。8 张照片按毕业 → 教学 → 聚餐 → 军训 → 汇演 → 自习 → 运动 → 旅行覆盖大学回忆的完整场景线Scroll 滚动流畅底部安全区内边距保证 Tab 栏可点。七、扩展思考相册的照片组织与浏览设计相册页是纪念册的内容层其照片组织可深入设计照片时间线8 张照片按场景排列产品化后应按时间线大一 → 大四或按主题分组毕业季/军训/活动——Photo接口加date字段即可支撑时间线浏览。照片详情点击照片全屏预览Swiper左右滑动切换 查看谁上传的、何时上传的、点赞——照片的元信息是纪念册的回忆注脚。协作标注照片支持同学标注这是谁、这一刻情感标签/——让照片可被集体共同解读是纪念册照片的社交属性。照片审核集体相册的成员上传需审核避免不当照片污染共同记忆——上传条的产品化需配套审核流程。原图与压缩照片墙用缩略图快详情用原图清晰——分层加载是相册产品的性能基础。八、扩展思考虚线上传条的交互设计虚线边框上传条是添加交互的视觉范式其设计价值值得展开虚线的语义虚线 此处有缺口等待填充——与实线已就绪形成对比用户本能理解可添加App 40 的虚线格、本页虚线上传条、邮箱的虚线附件框都是此语义。三元素组合图标 动作 文字说明 圆形按钮视觉焦点——一行内完成是什么 做什么 点哪里的三重表达用户零思考即可操作。整条热区点击挂整条而非仅按钮——扩大热区44dp 以上符合移动端触控规范。上传的后续反馈上传成功后虚线框变实线有照片、计数 1相册照片 (8) → (9)——填充缺口的视觉闭环让上传动作有明确的完成感。空相册引导若照片为 0上传条下方应显示空态引导还没有照片点击上方上传第一张——空态的引导设计是产品化的必备。九、开发者视角相册页的调试与验证技巧Grid 三列的边界8 张照片332三行、末行右格空缺——这是 Grid 自然布局若照片数为 1/2/4 等奇数末行左对齐正常验证时确认无错位。aspectRatio 的方形保证aspectRatio(1)依赖列宽推导高度——columnsTemplate(1fr 1fr 1fr)拼错会破坏方形调试先确认模板字符串。虚线边框的渲染BorderStyle.Dashed虚线在圆角 20 的卡片上可能锯齿——本页虚线条圆角 20 且边框完整真机确认虚线密度与圆角衔接。标题省略maxLines(1) Ellipsis width(100%)三件套——毕业旅行等 4 字无碍长标题图书馆自习室一角验证省略位置。上传计数的联动若实现上传照片后计数变化需photos数组增删 标题重渲染photos.length是响应式的——与 App 40 的photoCount状态机同模式。十、系列横向对比三款照片相关 App 的网格差异App 44 相册页是系列第三款照片网格三者的差异正好体现网格的设计弹性页面列数单元格附加元素场景App 44 相册3 列正方图标题虚线上传条班级相册App 40 上传3 列正方形✕ 角标/虚线格选图上传App 40 首页双列瀑布高度错落张数角标相册发现列数选择三款都用了 3 列正方形网格因为照片墙的方块感在 3 列下密度与清晰度最佳单图 1/3 屏宽可看清内容、屏内可见 9 张App 40 首页的瀑布流是发现场景突出封面大图相册页是浏览场景规整方格更高效。附加元素差异App 44 相册页有虚线上传条上传入口App 40 上传页有✕ 删除/添加格选择状态App 40 首页有张数角标信息标注——同一 3 列网格附加元素决定页面职能上传条生产入口、角标状态管理、数据信息展示。三款页面的网格实现几乎相同columnsTemplate(1fr 1fr 1fr)差异全在格子里放了什么 格子外配了什么这是 Grid 组件一套布局、多场景复用的最佳示范。十一、扩展思考班级相册的协作与回忆机制相册页不仅是照片墙更是班级协作与回忆的载体共同上传每位同学上传照片上传条——相册照片数8 → N随成员上传持续增长首页纪念册的 N 张同步更新——协作让相册越长越厚。照片的主人每张照片可记录上传者谁传的——集体相册中谁传了哪张是回忆的一部分看到照片想起这是小林拍的。照片的时间沉淀8 张照片从军训大一到毕业大四——按时间线排列即是大学四年的编年史照片墙自动成为时光档案。回忆的入口点击照片全屏预览 查看评论这天的军训好苦——照片引发的共同回忆是班级凝聚力的来源评论区留言页模式可挂在照片详情。纪念册的厚度首页 256 张是纪念册的厚度相册页是厚度的可见化——每翻一张照片都是一次青春的回放这是纪念册产品的情感核心。十二、FAQ 与一句话总结Q1相册页和首页纪念册什么关系首页是纪念册目录4 本册子相册页是当前册子的照片墙班级相册 8 张——目录 内容两级结构首页点开纪念册进入相册 Tab 对应照片集。Q2为什么是 3 列网格而不是瀑布流班级相册的照片是事件记录合影/聚餐/活动等大的 3 列网格适合规整浏览瀑布流适合高度错落的风景/作品照App 40 首页。照片的规整度决定网格形态。Q38 张照片是全部吗8 张是当前展示的照片数SectionTitle相册照片 (8)首页纪念册的 256 张是总数——展示样例与总量口径分层产品化后分页加载每页 N 张。Q4上传照片真实怎么实现PhotoViewPicker调起系统相册多选 → 压缩 → 上传服务端 → 刷新网格计数——Demo 的虚线框与 Toast 是这条链路的入口占位。Q5为什么照片也用 emoji 占位原型阶段 emoji 毕业合影零资源、场景直观真实产品替换为Image缩略图objectFit(ImageFit.Cover)裁切布局零改动。一句话总结相册页以虚线上传条 3 列照片网格完成了纪念册照片墙的展示与上传入口。虚线边框的待填充语义、28×28 圆形的视觉焦点、照片 标题的正方格、8 张照片覆盖大学完整回忆线——90 行代码一个让回忆有序铺展的班级相册也是上传即协作纪念册机制的内容层。十三、开发者视角相册页的调试与验证技巧Grid 三列的边界8 张照片332三行、末行右格空缺——Grid 自然布局若照片数变 9完美 3×3、104 行、1单张验证各行排布无错位这是照片数动态变化的基本回归。aspectRatio 的方形保证aspectRatio(1)依赖列宽推导高度——columnsTemplate(1fr 1fr 1fr)拼错多/少写 1fr会破坏方形与列数调试先确认模板字符串与预期一致。虚线边框的渲染BorderStyle.Dashed在圆角 20 卡片上的虚线密度与圆角衔接因机型而异——真机确认无锯齿、虚线清晰必要时调整 dash 参数。标题省略maxLines(1) Ellipsis width(100%)三件套缺一不可——毕业旅行等短标题无碍长标题图书馆自习室一角验证省略位置。上传计数的联动若实现上传照片后计数变化photos数组增删 SectionTitle 重渲染photos.length响应式——与 App 40 的photoCount状态机同模式注意 State 数组整体重赋值。十四、FAQ 与一句话总结Q68 张照片会随上传变多吗会——上传成功后photos数组追加、SectionTitle相册照片 (8)变 (9)首页纪念册 N 张同步 1这是上传 → 展示的数据闭环。Q7照片支持删除吗Demo 未实现。产品化后照片卡可长按/编辑删除权限上传者可删自己的照片、管理员可删任意删除后计数 -1——集体相册的删除需权限控制。Q8为什么上传条用虚线而不是实线虚线 待填充此处可添加实线 已就绪——上传条是添加入口用虚线语义最准App 40 的格同款实线留给正式的功能卡照片卡/信息卡。Q9照片能按时间排序吗Demo 按数组顺序毕业→旅行产品化后Photo加date字段按时间线排序即可展示大一军训 → 大四毕业的时光编年史——与首页纪念册的时间沉淀呼应。Q10班级相册只有照片没有视频Demo 仅照片产品化可扩展视频相册 Tab 支持照片/视频混排Grid 单元格加播放角标——回忆不仅定格还有动态是纪念册的自然演进。这些 FAQ 与前面的拆解共同构成本页的完整解析。最后从验收视角确认四张实机截图覆盖了首屏虚线上传条照片网格、上传条点击上传照片 Toast、照片点击毕业合影 Toast、完整视图8 照片全览四个状态虚线边框、正方形照片块、标题省略、整卡点击均验证正常。相册照片 (8)为当前展示的张数。整页 90 行代码完成上传入口 照片墙的班级相册验收通过可作为集体相册类页面的标准参考。补充一点相册页与首页的封面 emoji是同一套符号系统——首页纪念册封面用 ///⛰️册子主题相册页照片用 ///⛺////具体回忆场景两级 emoji 从主题到场景层层细化无需任何文字说明用户仅凭 emoji 就能感知这本册子记录了什么、这张照片是什么时刻。这种emoji 即索引的设计在原型阶段零成本、信息传达率极高产品化后替换为真实照片时emoji 的语义层级主题封面/场景照片也恰好对应了纪念册封面图/相册照片缩略图的数据结构迁移平滑无痛。另外上传条的 文字 圆形加号三元素布局与首页 Banner 标题 说明的图标 双行信息结构同源——系列所有入口卡共享同一套左图标、右文案的视觉语法用户在 App 内任何入口处都能零学习成本地识别这是可点击的入口这是统一设计语言带来的隐性效率。相册页 90 行代码因此承担了上传引导 回忆展示的双重职能完成度经得起推敲。最后以一段话收束相册篇相册页是纪念册的内容层——虚线上传条张开添加入口3 列网格铺展共同记忆8 张照片从毕业合影到毕业旅行串起大学四年的编年。它既是班级协作的成果展示照片由成员共同上传也是青春回放的时光机每张照片都是一次回忆。若开发者能从中带走一点那就是上传入口用虚线、照片格用正方形、计数用标题联动这一组照片墙的标准做法——它在本页的完成度已经足以作为集体相册类页面的参考模板。 每一张照片都是青春翻过的一页。 愿时光温柔回忆长存。