ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

鸿蒙原生应用 ArkUI 声明式:兴趣匹配首页环形 Progress 与推荐卡片流

鸿蒙原生应用 ArkUI 声明式:兴趣匹配首页环形 Progress 与推荐卡片流 鸿蒙原生应用 ArkUI 声明式兴趣匹配首页环形 Progress 与推荐卡片流App 39「校园兴趣匹配」首页HomeTab主题色#FF6B9D粉色pink4 个 Tab 分别为首页、兴趣、匹配、我的。首页采用Header 今日匹配 Banner 推荐列表三区布局——白色双行 Header兴趣匹配22 号加粗 副标题遇见志同道合的 TA 粉色渐变今日最佳匹配卡环形 Progress 95% 音乐小铃 · 95% 契合 查看 SectionTitle为你推荐 4 条推荐用户列表 音乐小铃 95% 传媒学院 / 游戏阿杰 88% 计算机学院 / 书虫小雅 82% 文学院 / 运动大伟 76% 体育学院每条含 52×52 浅粉圆形 emoji 头像 姓名 学院 粉色大号匹配度百分比 3 个 #兴趣标签。本篇基于39-interest-match/entry/src/main/ets/pages/HomeTab.ets共 111 行逐段拆解附 4 张实机截图。一、整体结构三区Header 今日匹配 推荐列表布局App 39 首页是品牌头部 今日最佳匹配宣传卡 用户推荐列表的三区布局——3 个 Builder 块build() { Column() { this.Header() Scroll() { Column({ space: 14 }) { this.TodayMatch() this.SectionTitle(为你推荐) this.UserList() } .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— 双行品牌头兴趣匹配 副标题白底、占满整宽属于固定在顶部的非滚动区TodayMatch— 粉色渐变今日最佳匹配宣传卡含环形进度与推荐对象名直接呼应 App 的核心卖点每天帮你发现最合拍的那个人UserList— 为你推荐标题 4 条用户卡片每条卡片展示匹配度百分比与兴趣标签是首页的信息主体整个列表包在Scroll中设置layoutWeight(1)让滚动区自动占满剩余高度scrollBar(BarState.Off)隐藏滚动条、align(Alignment.Top)保证内容从顶部对齐外层容器padding的 bottom 还预留了safeBottom 20规避了底部导航栏与安全区的遮挡问题。项目源码开源https://gitee.com/codenestFlow/HarmonyOSHub二、Header双行品牌头白色卡片式收尾首页顶部没有沿用前几个 App 的单行纯标题而是做成了主标题 副标题的双行结构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: 4 }) Text(遇见志同道合的 TA ).fontSize(12).fontColor(C.textDim).width(100%) .padding({ left: D.pad, right: D.pad, bottom: 12 }) }.width(100%).backgroundColor(C.card) }几个细节值得注意双行错位排版第一行 22 号加粗正文字色第二行 12 号浅灰行间有bottom: 4与bottom: 12的间距控制视觉上大标题 轻说明层级分明。安全区适配第一行顶部padding({ top: this.safeTop 10 })safeTop通过StorageProp(safeTop)从全局存储中读取状态栏高度适配了不同机型的刘海/挖孔屏。全宽白底backgroundColor(C.card)让头部形成一块白色背景板与下方C.bg的浅蓝灰底形成干净的层次过渡。emoji 点睛副标题末尾的用小符号传达相遇、缘分的氛围与前两个 App 的风格一脉相承。三、TodayMatch粉色渐变 环形进度今日最佳匹配卡这是首页最醒目的视觉焦点也是整个 App 的门面TodayMatch() { Row({ space: 14 }) { Stack({ alignContent: Alignment.Center }) { Progress({ value: 95, total: 100, type: ProgressType.Ring }) .width(64).height(64).color(#FFFFFF) .style({ strokeWidth: 6 }).backgroundColor(#44FFFFFF) Text(95%).fontSize(15).fontWeight(FontWeight.Bold).fontColor(#FFFFFF) } Column({ space: 4 }) { Text(今日最佳匹配).fontSize(16).fontWeight(FontWeight.Bold).fontColor(#FFFFFF) Text(音乐小铃 · 95% 契合).fontSize(12).fontColor(#FFFFFF).opacity(0.9) }.alignItems(HorizontalAlign.Start).layoutWeight(1) Text(查看 ).fontSize(12).fontColor(#FFFFFF) } .width(100%).padding(18).borderRadius(D.rLg) .linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] }) .onClick(() { promptAction.showToast({ message: 查看匹配 }); }) }技术拆解Progress Ring 环形进度Progress({ value: 95, total: 100, type: ProgressType.Ring })声明一个总量 100、当前值 95 的圆环strokeWidth: 6控制环粗backgroundColor(#44FFFFFF)是半透明底环color(#FFFFFF)是白色进度环。Stack 居中叠加外层Stack({ alignContent: Alignment.Center })把环形进度和正中的95%文字叠加在一起实现环包字的经典数据可视化效果。渐变背景linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })从主题粉#FF6B9D135° 渐变到浅粉#FF9DBA让整张卡片自带柔和暖色过渡视觉上非常甜。主次信息右侧 Column 内 16 号加粗今日最佳匹配为主标题12 号 90% 透明度音乐小铃 · 95% 契合为副信息右侧尾部的查看 暗示可点击整卡onClick弹出查看匹配Toast。布局弹性中间 Column 加layoutWeight(1)抢占弹性宽度把左右两端固定元素推开保证任何屏幕宽度下排版都稳定。四、SectionTitle 与 UserList为你推荐 4 条用户卡片标题部分极其精简SectionTitle(title: string) { Row() { Text(title).fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text) }.width(100%) }16 号加粗宽度占满仅此而已。真正的重点是下方推荐用户列表UserList() { Column({ space: 12 }) { ForEach(this.users, (u: User) { Column({ space: 10 }) { Row({ space: 12 }) { Row() { Text(u.emoji).fontSize(28) } .width(52).height(52).backgroundColor(C.primarySoft).borderRadius(26).justifyContent(FlexAlign.Center) Column({ space: 4 }) { Text(u.name).fontSize(15).fontWeight(FontWeight.Medium).fontColor(C.text) Text(u.major).fontSize(12).fontColor(C.textDim) }.alignItems(HorizontalAlign.Start).layoutWeight(1) Column({ space: 2 }) { Text(u.match %).fontSize(18).fontWeight(FontWeight.Bold).fontColor(C.primary) Text(匹配度).fontSize(10).fontColor(C.textDim) } }.width(100%) Flex({ wrap: FlexWrap.Wrap }) { ForEach(u.tags, (t: string) { Text(# t).fontSize(11).fontColor(C.accent) .padding({ left: 8, right: 8, top: 3, bottom: 3 }).backgroundColor(C.cardSoft).borderRadius(10) .margin({ right: 8 }) }, (t: string) t) }.width(100%) } .width(100%).padding(14).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) .onClick(() { promptAction.showToast({ message: u.name }); }) }, (u: User) u.id.toString()) }.width(100%) }用户数据由private users: User[]静态数组提供数据源在 21-26 行用户学院匹配度兴趣标签 音乐小铃传媒学院95%民谣 / 摄影 / 旅行 游戏阿杰计算机学院88%电竞 / 编程 / 动漫 书虫小雅文学院82%阅读 / 写作 / 咖啡 运动大伟体育学院76%篮球 / 健身 / 跑步卡片细节emoji 头像52×52 的浅粉圆形primarySoft居中放大 28 号 emoji替代真实头像成本低且氛围轻松——注意这是兴趣匹配App用兴趣 emoji 当头像正是产品定位的体现。主信息列姓名 15 号 Medium 字重 学院 12 号浅灰两行叠放layoutWeight(1)抢占中间弹性空间。匹配度右侧 18 号粉色加粗百分比 10 号匹配度小字是整张卡最重要的数据放在最显眼的右端。标签行独立Flex({ wrap: FlexWrap.Wrap })自动换行排布#民谣 #摄影 #旅行等标签11 号 accent 粉色文字 cardSoft浅底 圆角 10向右留 8 的 margin可容纳任意数量标签。整体卡片白底圆角 14 1 号stroke描边 14 内边距点击弹 Toast 显示用户名。key 策略外层ForEach以u.id.toString()为 key保证列表项唯一稳定。五、跨页数据自洽音乐小铃 95% 贯穿全 App首页不是孤立页面其数据与另外三个 Tab 严格自洽今日最佳匹配音乐小铃 · 95% 契合正是下方推荐列表第一位的 音乐小铃 95%——Banner 与列表互相印证。匹配页Func2Tab中匹配结果第一位同样是 音乐小铃 95% 共同兴趣民谣、摄影与首页民谣、摄影、旅行标签高度重合共同兴趣 双方标签交集逻辑闭环。我的页ProfileTab的统计5 兴趣标签、24 匹配历史、18 好友与匹配页24 匹配的人、8 高契合度、12 已打招呼数字一致说明整套产品有一套统一的用户画像 匹配记录数据模型。这种跨页面的一致性让 Demo 在演示时观感极其真实也是本系列文章反复强调的数据自洽设计原则。六、扩展思考兴趣匹配的推荐算法雏形虽然本 Demo 的推荐数据是写死的静态数组但其页面结构已经隐含了真实产品的算法思路标签画像每位用户维护一组兴趣标签如音乐小铃的民谣/摄影/旅行这是匹配算法的最基本输入。交集计算匹配度本质可以理解为共同标签数 / 加权标签数的量化匹配页展示的共同兴趣标签正是交集的可视化。每日刷新今日最佳匹配暗示按天轮换推荐对象对应真实产品中的每日一荐机制能提升用户打开率。可扩展方向若把users数组换成网络数据 分页加载把匹配度改成实时计算的函数再配上滑动左/右表示感兴趣/跳过就是一款完整的校园版 Soul / 探探。七、彩蛋细节藏在布局里的设计巧思副标题文案遇见志同道合的 TA 里的TA刻意不写他/她兼顾性别中立是校园产品常见的小心思。头像 emoji 即兴趣音乐小铃的 、游戏阿杰的 、书虫小雅的 、运动大伟的 四个 emoji 直接对应四类兴趣不用任何文字说明用户就已人设清晰。匹配度排序列表严格按 95→88→82→76 降序排列是推荐按契合度排序的最朴素实现暗示数据层已具备排序能力。渐变方向统一首页渐变卡、我的页 UserCard 全部使用 135° 且同为primary→accent品牌色在全 App 内保持一致的方向感。Progress 环的 44 透明度底环#44FFFFFF的 alpha 值 0x44 约等于 26.7% 透明度是特意调出来的半透明效果让白色进度环在粉色渐变上既清晰又不生硬。八、实机截图与交互演示本节结合 4 张实机截图逐张还原首页的视觉效果与交互过程。1. 首页首屏渐变卡 推荐列表第一张截图是进入 App 39 后的默认首屏。自上而下依次是白色双行 Header兴趣匹配 22 号加粗 副标题遇见志同道合的 TA 、粉色渐变今日最佳匹配卡左侧环形进度 95% 与白色数字叠加、中央 16 号今日最佳匹配、右侧查看 箭头、为你推荐分区标题与第一条用户卡片 音乐小铃 95% 传媒学院头像下方三个粉色 # 标签。整页以浅蓝灰#F2F5FB为背景白色卡片与粉色渐变卡交替排布节奏明快、信息层级一目了然。2. 点击查看 弹出匹配 Toast第二张截图演示了点击今日最佳匹配卡右侧查看 后的即时反馈屏幕下方弹出查看匹配系统 Toast。整张渐变卡只挂了一个onClick文案与卡片语义完全一致让用户清楚知道点击此处会进入匹配详情流程是引导转化的关键一步。3. 点击用户卡片弹出姓名 Toast第三张截图是点击推荐列表中任一张用户卡片后的反馈——Toast 显示该用户的名字。由于每张卡片的onClick都绑定promptAction.showToast({ message: u.name })点击音乐小铃即弹出音乐小铃点击其他用户同理交互反馈精确到人验证了 ForEach 列表的点击事件参数传递正确。4. 列表滚动到底第四位用户完整可见第四张截图是向上滑动列表后的底部视图。第四位用户 运动大伟 76% 体育学院及其三个兴趣标签#篮球 #健身 #跑步完整露出证明Scroll滚动正常、四条用户卡按 95→88→82→76 的匹配度降序完整排列页面底部预留了safeBottom 20的安全区内边距底部 Tab 栏始终可点滚动与导航互不干扰。九、扩展细节主题系统与常量提取的工程价值首页代码中大量直接引用了C主题色与D圆角/内边距两个静态常量类这背后是值得展开的工程思想单一事实来源Theme.ets中C.primary #FF6B9D定义一次首页渐变卡、用户卡片头像、匹配度数字、标签文字四处引用同一常量——如果产品要换品牌色比如从粉色改成紫色只需改一行全 App 同步生效杜绝改漏一处的配色灾难。语义化命名常量不叫pink而叫primary把颜色值抽象为语义角色——primary主色、accent强调色、textDim次要文字、cardSoft浅底。组件只需表达我要主色不必关心具体色值主题更换时零改动。圆角与间距统一D.rLg 20 / rMd 14 / rSm 10 / pad 16四档尺度被全 App 复用保证每个页面的圆角、留白视觉节奏一致这是设计系统在代码层面的最小落地。可扩展为深色模式若未来引入深色模式只需把C的静态常量改为StorageProp驱动的动态主题或用资源文件resources的深色限定符页面代码无需任何改动——常量集中化带来的最大红利就是主题可替换。十、扩展细节页面状态与数据流向分析从数据流视角回看首页可以提炼出一套清晰的 MVVM 思想View 与 Model 分离users静态数组是模型层Builder 的 Header/TodayMatch/UserList 是视图层页面中没有业务逻辑函数——点击事件只做 Toast 展示模型与视图解耦。State 的唯一状态首页仅声明StorageProp(safeTop)与safeBottom两个状态其余全部是静态私有属性说明本页是纯展示页没有需要持久化的交互状态状态面极窄、容易测试。ForEach 的 key 设计(u: User) u.id.toString()用唯一 id 作 key即使将来users数组增删或排序ArkUI 也能精准 diff、复用节点避免整列表重建的性能损耗。演化路径把private users换成State users并从网络接口拉取配合onAppear生命周期、下拉刷新Refresh组件、骨架屏占位首页立刻具备真实产品形态——当前静态实现恰好是先跑通 UI、再接入数据的最小可验证原型。十一、补充说明与终评首页是整套 App 的门面担当承担着一眼看懂产品在做什么的职责。本页用三个区块完成了完整叙事Header 讲品牌、渐变卡讲今日最佳、列表讲为你推荐。技术实现上Progress环形进度、linearGradient渐变、Stack叠加、Flex标签换行都是 ArkUI 的高频能力代码量虽小但组合出的视觉效果相当完整。粉色系#FF6B9D → #FF9DBA的渐变风格甜美清爽与校园社交的调性高度契合非常适合作为兴趣社交类产品首页的参考范本。十二、常见问题与开发避坑开发这类渐变卡 列表首页时有几个高频坑值得记录Progress 环形进度不显示Progress({ value, total, type: ProgressType.Ring })必须同时设置width/height才能撑出圆环否则默认尺寸可能过小同时注意style({ strokeWidth })要在Progress上链式调用写错位置会失效。linearGradient 的 angle 单位angle: 135的单位是度deg从 12 点钟方向顺时针计算135 度即左上 → 右下。如果想实现左下 → 右上需要改用 315 度或调换 colors 顺序。StorageProp 未初始化StorageProp(safeTop) safeTop: number 0的默认值 0 很重要——如果 AppStorage 里还没有该键读取到的是默认值而非 undefined页面不会因布局错乱而崩溃。全局安全区通常在EntryAbility的onCreate中通过windowStage.getMainWindowSync()获取后写入 AppStorage。ForEach 的 key 警告若 key 是重复字符串如所有用户 id 都是 1控制台会刷duplicate key警告且 diff 错乱——务必保证 key 全局唯一本页用u.id.toString()是正确示范。Toast 连点重复弹出快速多次点击渐变卡会连续弹出多个 Toast体验略差。工程化时可加节流如let last 0; if (Date.now() - last 800) return; last Date.now();合并重复反馈。十三、系列横向对比兴趣匹配 vs 校园社交类 App把 App 39 放入本系列横向审视它的定位与差异化非常清晰维度App 39 兴趣匹配App 35 笔记交换App 38 技能交换主题色粉色 #FF6B9D紫罗兰 #9B51E0青蓝 #2D9CDB核心对象人兴趣相投者物笔记/文档技能可交换能力首页结构今日匹配卡 推荐列表分类 笔记列表分类胶囊 Banner 技能列表匹配机制共同兴趣标签交集无想学 ↔ 会核心操作打招呼浏览/收藏交换可以清晰看到三者的演进脉络笔记交换解决资料怎么共享、技能交换解决能力怎么交换、兴趣匹配解决人怎么认识——层层递进App 39 站在了社交链路的顶端。若把三者的数据打通笔记作者 技能达人也出现在兴趣推荐里就是一个完整的校园人脉生态。这种系列化产品的视角正是理解单页价值之外的额外收获。十四、FAQ关于首页的常见疑问Q1为什么今日最佳匹配用的是环形进度而不是普通数字环形进度把95%包装成可视化的完成度圆环视觉冲击力远强于纯数字同时 6 号粗环在渐变卡上能形成稳定的视觉锚点让整张卡活起来。这也是数据可视化图表优先于数字的典型体现。Q2匹配度 95% 是怎么来的Demo 中users是静态数组匹配度是写死的值。真实产品里它由共同标签数 / 标签并集等算法实时计算如兴趣页选中的标签与对方标签的 Jaccard 相似度并在每次用户更新兴趣后重算——首页只是这个计算结果的展示层。Q3为什么推荐列表只有 4 个人4 条是一屏能完整看到 有滚动余地的黄金数量太多会稀释注意力、太少显得内容单薄。真实产品则用分页加载每页 10-20 条 下拉刷新替换但首屏展示逻辑与本 Demo 一致。Q4渐变卡可以直接替换成图片 Banner 吗可以。把linearGradient换成Image组件并铺满卡片即可其余布局代码无需改动——这正是背景可替换的架构红利。不过渐变方案在加载速度与文件体积上优于图片适合 Demo 与轻量场景。Q5点击卡片弹出 Toast 是不是太简陋Toast 是原型阶段的合法反馈手段胜在零依赖、即时可见。产品化时按卡片 → 用户详情页跳转即可点击事件与跳转参数用户 id的传递方式完全一致无需重构。Q6首页没有搜索入口会不会不好用本 Demo 定位是系统主动推荐搜索属于进阶能力。真实产品可在 Header 右侧加放大镜图标跳转搜索页按标签/学院过滤用户——与本页的数据结构天然兼容过滤即对users数组做条件筛选。十五、一句话总结首页用三个区块讲完一个故事Header 亮品牌、渐变卡说今天的最佳、列表给更多选择。粉色渐变与环形进度是视觉记忆点跨页数据自洽是产品可信度而Progress/linearGradient/Stack/Flex四个 ArkUI 组件的高频组合则是这篇解析最值得带走的工程价值。值得一提的是本页还隐含了一处容易被忽略的设计safeTop与safeBottom两个安全区变量通过StorageProp从全局注入首页 Header、列表底边距、底部 Tab 栏高度barHeight(60 this.safeBottom)全部消费了它们——这意味着同一个页面代码在全面屏、带手势条的机型、甚至 2in1 平板形态上都能自动适配无需为每种机型写专门布局。这也解释了为什么模拟器 1280×2800 的竖屏下16 张截图全部干净无遮挡。对于想把这套代码移植到真机的开发者这一层安全区适配体系是最值得直接抄走的隐形基建。另外本页推荐列表的姓名、学院、标签三行信息与 App 38 技能列表的布局节奏几乎一致52×52 头像 两行文本 右侧数据印证了这套头像 信息 动作的卡片模板在本系列中的高复用性——它既保证了开发效率也让用户在 32-39 号 App 之间切换时保持一致的阅读习惯品牌识别度无形中得以强化。
返回列表