鸿蒙原生应用 HarmonyOS ArkTS:社交匹配首页的环形进度与在线状态点

发布时间:2026/9/7 18:10:45
鸿蒙原生应用 HarmonyOS ArkTS:社交匹配首页的环形进度与在线状态点 鸿蒙原生应用 HarmonyOS ArkTS社交匹配首页的环形进度与在线状态点App 18「校园社交匹配」首页HomeTab主题色#EC4899粉红4 个 Tab 分别为首页、发现、消息、我的。首页采用固定 Header 粉红渐变推荐卡今日推荐/同好匹配数/智能匹配说明独立搜索栏 3 栏统计 4 个圆形入口 本周匹配趋势条形图 4 张推荐同好卡匹配度环形进度 在线状态点 兴趣标签 跳过/打招呼双按钮 兴趣排行榜带涨跌箭头。本篇基于18-social-match/entry/src/main/ets/pages/HomeTab.ets约 244 行逐段拆解附 4 张实机截图。一、整体结构8 个 Builder 的内容流HomeTab 在系列首页模板基础上新增了 2 个模块独立 SearchBar、PersonList共 8 个 Builderbuild() { Column() { this.Header() Scroll() { Column({ space: 14 }) { this.HeroCard() this.SearchBar() this.StatRow() this.QuickActionRow() this.WeekChart() this.SectionTitle(推荐同好) this.PersonList() this.SectionTitle(兴趣排行) this.RankList() } .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) }8 个块按品牌 → 搜索 → 数据 → 入口 → 图表 → 推荐 → 排行叙事Header— 校园交友 Slogan品牌区HeroCard— 今日推荐渐变卡情感化SearchBar— 独立搜索栏区别于嵌在 HeroCard 里的 App 14/15/16StatRow— 3 栏统计今日匹配/好友总数/互动次数QuickActionRow— 4 个圆形入口找同好/兴趣群/活动/匿名墙WeekChart— 本周匹配趋势条形图SectionTitle(推荐同好) PersonList— 4 张同好卡本页核心SectionTitle(兴趣排行) RankList— 4 条兴趣排行带涨跌对比 App 13/17音乐/志愿首页App 13/17 是Hero 兼搜索App 18 是独立 SearchBar——独立搜索栏更醒目搜索是社交 App 的高频操作值得独立占位。项目源码开源https://gitee.com/codenestFlow/HarmonyOSHub二、Header HeroCard社交品牌区Header 是校园交友/找到兴趣相投的小伙伴 两行品牌区与 App 14/15/16 同构。HeroCard 是横向布局的情感化推荐卡Builder HeroCard() { Row({ space: 14 }) { Column({ space: 6 }) { Text(今日推荐).fontSize(12).fontColor(#FFFFFF).opacity(0.85) Text(4 位同好等你匹配).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#FFFFFF) Text(基于兴趣标签智能匹配).fontSize(11).fontColor(#FFFFFF).opacity(0.75) }.alignItems(HorizontalAlign.Start).layoutWeight(1) Text().fontSize(44) } .width(100%).padding(20).borderRadius(D.rLg) .linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] }) .onClick(() { promptAction.showToast({ message: 刷新推荐 }); }) }今日推荐 / 4 位同好等你匹配 / 基于兴趣标签智能匹配三行——标题 主信息 说明的情感化文案结构。与 App 14 的运动会报名、App 15 的减碳种树、App 16 的限时抽奖一样——HeroCard 承载这个 App 的核心价值主张。横向布局Row 而非 Column左 3 行文案 右 大图标44sp。大 emoji 让 HeroCard 更活泼——社交 App 需要亲和力。onClick(() { promptAction.showToast({ message: 刷新推荐 }); })整卡可点刷新推荐交互占位。三、SearchBar独立搜索栏SearchBar 是独立于 HeroCard 的搜索栏社交 App 的特色Builder SearchBar() { Row({ space: 8 }) { Text().fontSize(16).margin({ left: 12 }) TextInput({ placeholder: 搜索昵称、兴趣、学院..., text: this.searchText }) .onChange((val: string) { this.searchText val; }) .backgroundColor(transparent).borderRadius(D.rMd).height(40) .layoutWeight(1).placeholderColor(C.textDim).placeholderFont({ size: 13 }) } .width(100%).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) } 图标 TextInput 透明背景的组合——TextInput 用backgroundColor(transparent)透明 图标放左边。占位 搜索昵称、兴趣、学院...明确搜索范围3 个维度——占位符 搜索提示。State searchText: string 双向绑定——输入实时更新。真实项目应联动 PersonList 过滤按昵称/标签/学院模糊匹配。独立搜索栏 vs Hero 内嵌搜索App 14/15/16 的搜索在 HeroCard 里半透明白App 18 的搜索独立成白色卡片——独立搜索栏更通用微信/抖音的搜索都在顶部独立。四、StatRow QuickActionRow数据与入口StatRow 是 3 栏统计今日匹配 4/好友总数 56/互动次数 128数字全部C.primary粉红加粗Builder StatRow() { Row() { ForEach(this.stats, (s: StatItem) { Column({ space: 4 }) { Text(s.value).fontSize(20).fontWeight(FontWeight.Bold).fontColor(C.primary) Text(s.label).fontSize(11).fontColor(C.textDim) }.layoutWeight(1) }, (s: StatItem) s.label) } .width(100%).padding({ top: 14, bottom: 14 }) .backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) }与 App 14/15/16 的差异App 14/15/16 统计是3 栏彩色每个数字不同色App 18 是3 栏同粉红——社交 App 用统一主题色数字都是品牌色强化粉红社交的调性。统计色策略跟随业务。数据一致性今日匹配 4 HeroCard4 位同好、好友总数 56 我的页好友 56、互动次数 128 我的页互动 128——跨页数据一致✓。QuickActionRow4 个圆形入口找同好/兴趣群/活动/匿名墙Builder QuickActionRow() { Row() { ForEach(this.actions, (a: QuickAction) { Column({ space: 8 }) { Row() { Text(a.icon).fontSize(22) } .width(48).height(48).backgroundColor(C.primarySoft).borderRadius(24).justifyContent(FlexAlign.Center) Text(a.label).fontSize(11).fontColor(C.textSub) }.layoutWeight(1).onClick(() { promptAction.showToast({ message: a.label }); }) }, (a: QuickAction) a.id.toString()) } .width(100%).padding({ top: 14, bottom: 14 }) .backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) }48×48 正圆borderRadius(24)C.primarySoft浅粉红底——4 个社交功能入口找同好/兴趣群/活动/匿名墙覆盖社交 App 的核心玩法。五、WeekChart本周匹配趋势WeekChart 与系列周图同构7 天条形图但柱体渲染更简洁Builder WeekChart() { Column({ space: 10 }) { Row() { Text(本周匹配趋势).fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text) Blank() Text(共 500 次).fontSize(11).fontColor(C.textDim) }.width(100%) Row() { ForEach(this.weekBars, (b: BarItem) { Column({ space: 6 }) { Column().width(14).height(b.value * 0.7).backgroundColor(C.primary).borderRadius(4) Text(b.day).fontSize(10).fontColor(C.textDim) }.layoutWeight(1) }, (b: BarItem) b.day) }.width(100%).alignItems(VerticalAlign.Bottom).height(90) } .width(100%).padding(14).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) }差异点height(b.value * 0.7)直接用倍数60×0.742vp而非value / max * maxHeight归一化——**固定倍率**更简单max100 时 100×0.770vp纯色柱C.primary单色而非渐变柱——简化版alignItems(VerticalAlign.Bottom) 容器height(90)让柱子从底部长起来数据一 60/二 80/三 45/四 90/五 70/六 100/日 55——周六 100 最高周末社交高峰、周三 45 最低工作日低谷——周末匹配多符合社交规律。共 500 次608045907010055 500——汇总严格等于各柱之和✓。六、PersonList推荐同好卡本页核心PersonList 是 4 张推荐同好卡每张含匹配度环形进度、在线状态点、兴趣标签、跳过/打招呼双按钮Builder PersonList() { Column({ space: 12 }) { ForEach(this.persons, (p: Person) { Column({ space: 12 }) { Row({ space: 12 }) { Stack({ alignContent: Alignment.BottomEnd }) { Row() { Text(p.avatar).fontSize(36) } .width(56).height(56).backgroundColor(C.primarySoft).borderRadius(28).justifyContent(FlexAlign.Center) Row() { Text().width(12).height(12).backgroundColor(p.online ? C.ok : C.textDim).borderRadius(6).border({ width: 2, color: C.card }) } } Column({ space: 4 }) { Row({ space: 6 }) { Text(p.name).fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text) Text(⭐ p.rating .0).fontSize(10).fontColor(C.warn) } Text(p.dept).fontSize(12).fontColor(C.textDim) }.alignItems(HorizontalAlign.Start).layoutWeight(1) Stack({ alignContent: Alignment.Center }) { Progress({ value: p.match, total: 100, type: ProgressType.Ring }).width(44).height(44).color(C.primary).style({ strokeWidth: 4 }) Text(p.match %).fontSize(11).fontColor(C.primary).fontWeight(FontWeight.Bold) } }.width(100%) Row({ space: 8 }) { ForEach(p.tags, (t: string, idx: number) { Text(t).fontSize(11).fontColor(C.primary) .padding({ left: 8, right: 8, top: 4, bottom: 4 }) .backgroundColor(C.primarySoft).borderRadius(4) }, (t: string, idx: number) t idx) }.width(100%) Row({ space: 12 }) { Button(跳过).fontSize(13).fontColor(C.textSub).backgroundColor(C.cardSoft) .borderRadius(D.rMd).height(38).layoutWeight(1) .onClick(() { promptAction.showToast({ message: 已跳过 }); }) Button(打招呼).fontSize(13).fontColor(#FFFFFF).backgroundColor(C.primary) .borderRadius(D.rMd).height(38).layoutWeight(1) .onClick(() { promptAction.showToast({ message: 打招呼: p.name }); }) }.width(100%) } .width(100%).padding(14).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke }) }, (p: Person) p.id.toString()) }.width(100%) }6.1 匹配度环形进度ProgressType.Ring——本页最大亮点Stack({ alignContent: Alignment.Center }) { Progress({ value: p.match, total: 100, type: ProgressType.Ring }).width(44).height(44).color(C.primary).style({ strokeWidth: 4 }) Text(p.match %).fontSize(11).fontColor(C.primary).fontWeight(FontWeight.Bold) }ProgressType.Ring是环形进度——本系列第一次用环形之前全是 Linear 线性value: p.match匹配度 92/85/78/80total: 100百分比总量.style({ strokeWidth: 4 })— 环粗细 4vpStack中心叠Text(p.match %)—环形 中间数字双通道匹配度 92% 85% 80% 78%——4 个人匹配度递减用户一眼看出谁和我最合拍。环形 vs 线性环形适合单个百分比强调匹配度是卡片的核心指标环形让它最醒目线性适合多条对比周图 7 根柱子。环形单点强调、线性批量对比是图表选择原则。6.2 在线状态点Stack BottomEndStack({ alignContent: Alignment.BottomEnd }) { Row() { Text(p.avatar).fontSize(36) } .width(56).height(56).backgroundColor(C.primarySoft).borderRadius(28).justifyContent(FlexAlign.Center) Row() { Text().width(12).height(12).backgroundColor(p.online ? C.ok : C.textDim).borderRadius(6).border({ width: 2, color: C.card }) } }头像右下角叠 12×12 状态点Stack BottomEnd在线 →C.ok绿色离线 →C.textDim灰色border({ width: 2, color: C.card })白色描边让绿点浮在头像上绿点在线、灰点离线是社交 App 的标准微信/QQ 同款。4 个人3 在线 1 离线小明/小美/小雪在线小华离线——数据有区分度。6.3 姓名 星级 学院Row({ space: 6 }) { Text(p.name).fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text) Text(⭐ p.rating .0).fontSize(10).fontColor(C.warn) } Text(p.dept).fontSize(12).fontColor(C.textDim)⭐5.0用⭐ rating .0字符串拼接简化星级不用 5 颗星——**数字星级vs星形星级**两种写法App 14 用 ★★★★☆App 18 用 ⭐5.0——App 18 更省空间配合环形进度。6.4 兴趣标签 双按钮兴趣标签ForEach(p.tags)粉红字 浅粉红底小胶囊——编程/动漫/篮球等兴趣即匹配依据用户一眼看到我和他有哪些共同兴趣。双按钮Row({ space: 12 }) { Button(跳过).fontSize(13).fontColor(C.textSub).backgroundColor(C.cardSoft) .borderRadius(D.rMd).height(38).layoutWeight(1) .onClick(() { promptAction.showToast({ message: 已跳过 }); }) Button(打招呼).fontSize(13).fontColor(#FFFFFF).backgroundColor(C.primary) .borderRadius(D.rMd).height(38).layoutWeight(1) .onClick(() { promptAction.showToast({ message: 打招呼: p.name }); }) }跳过灰底灰字次级— 不喜欢这个人打招呼粉红底白字主操作— 主动建立联系跳过/打招呼是交友 App 的核心双操作Soul/探探的左滑/右滑实体按钮版。主操作 次操作的视觉权重差异粉红 vs 灰引导用户点打招呼。七、RankList兴趣排行带涨跌RankList 是 4 条兴趣排行榜带排名数字、人数、涨跌箭头Builder RankList() { Column({ space: 0 }) { ForEach(this.ranks, (r: RankItem, idx: number) { Row({ space: 12 }) { Text(r.rank.toString()).fontSize(16).fontWeight(FontWeight.Bold) .fontColor(r.rank 3 ? C.primary : C.textDim).width(28).textAlign(TextAlign.Center) Text(r.name).fontSize(14).fontColor(C.text).layoutWeight(1) Text(r.count 人).fontSize(12).fontColor(C.textSub) Text(r.trend).fontSize(14).fontColor(r.trend ↑ ? C.ok : C.danger).margin({ left: 8 }) } .width(100%).padding({ left: 14, right: 14, top: 12, bottom: 12 }) if (idx this.ranks.length - 1) { Divider().color(C.stroke).strokeWidth(0.5) } }, (r: RankItem) r.id.toString()) } .width(100%).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) }4 条兴趣编程 234 人↑ / 动漫 198 人↑ / 篮球 156 人↓ / 音乐 142 人↑。涨跌箭头Text(r.trend).fontSize(14).fontColor(r.trend ↑ ? C.ok : C.danger).margin({ left: 8 })↑ 涨→C.ok绿色↓ 跌→C.danger红色↑绿 ↓红涨跌色是金融/榜单的标准股票涨绿跌红在中国市场涨红跌绿在国外——App 18 用↑绿 ↓红是国际惯例还是中国惯例其实中国股市是红涨绿跌App 18 用了绿涨红跌国际惯例——值得注意的设计选择。排名数字 1-4 用r.rank字段而非 idx1——rank 字段 vs 下标字段更灵活可以跳号下标更省事。前 3 名粉红加粗r.rank 3第 4 名灰色——前三名高亮。Divider().color(C.stroke).strokeWidth(0.5)0.5vp 超细分隔线比默认 1vp 更精致——细分隔线 高级感。八、State 与数据一致性HomeTab 只有1 个 StatesearchText搜索框文字。其余数据private不可变。4 组数据跨页一致好友总数 56 我的页好友 56互动次数 128 我的页互动 1284 位同好 我的页活动 12不直接对应但今日匹配 4 HeroCard4 位同好小明/小美/小华/小雪 消息页聊天对象同名 ✓推荐同好的 4 个人小明/小美/小华/小雪与消息页的 4 个聊天对象同名同头像——跨页人物一致是社交 App 的数据闭环首页推荐的人 → 消息页可以聊天。九、推荐卡的数据编排与匹配度叙事App 18 首页 4 张推荐同好卡的数据编排非常讲究匹配度叙事private persons: Person[] [ { id: 1, avatar: ‍, name: 小明, dept: 计算机学院, tags: [编程, 动漫, 篮球], match: 92, rating: 5, online: true }, { id: 2, avatar: ‍, name: 小美, dept: 艺术学院, tags: [绘画, 音乐, 旅行], match: 85, rating: 4, online: true }, { id: 3, avatar: ‍, name: 小华, dept: 化学学院, tags: [摄影, 电影, 桌游], match: 78, rating: 4, online: false }, { id: 4, avatar: ‍, name: 小雪, dept: 文学院, tags: [阅读, 写作, 烘焙], match: 80, rating: 5, online: true } ];4 人的匹配度梯度92% → 85% → 80% → 78% 递减——最合拍的排最前推荐排序 匹配度排序。用户从上往下看匹配度从高到低最好的先看是推荐列表的核心逻辑。4 人的差异化头像不同程序员/画家/科学家/阅读者——头像即人设学院不同计算机/艺术/化学/文学院——跨学院推荐社交 App 的推荐广度兴趣不同编程/动漫/篮球 vs 绘画/音乐/旅行——标签差异化状态不同3 在线 1 离线——状态差异化匹配度的算法暗示92% 的小明计算机学院 编程/篮球与用户匹配度最高——**匹配度 学院 兴趣标签的重合度**的视觉暗示。真实项目里匹配度由算法计算兴趣重合/学院距离/活跃度加权demo 用固定值演示推荐排序。匹配度叙事的可扩展真实项目应支持排序切换按匹配度/按距离/按活跃度排序、筛选只看在线/只看同学院、滑动卡片左滑跳过/右滑打招呼的 Tinder 式交互——推荐列表是社交 App 的核心demo 是简化版。十、排行榜的涨跌语义与数据治理App 18 兴趣排行榜的↑绿 ↓红涨跌箭头是**趋势数据的视觉表达**private ranks: RankItem[] [ { id: 1, rank: 1, name: 编程, count: 234, trend: ↑ }, { id: 2, rank: 2, name: 动漫, count: 198, trend: ↑ }, { id: 3, rank: 3, name: 篮球, count: 156, trend: ↓ }, { id: 4, rank: 4, name: 音乐, count: 142, trend: ↑ } ];编程/动漫/音乐涨、篮球跌——3 涨 1 跌让排行有变化感不全是↑也不全是↓。涨跌混合是排行榜的真实形态全部↑会显得假。trend: ↑用箭头字符串做字段——渲染时r.trend ↑ ? C.ok : C.danger判断颜色——字符串枚举 三元着色。真实项目应存布尔isRising: boolean或数字trendDelta: 22更严谨——箭头字符串是 demo 的简化真实项目要存涨跌幅数值才能显示22%。排行榜的数据驱动排序真实项目排行应后端实时计算按兴趣人数倒序demo 是静态数组。编程 234 人是校园编程社的规模暗示——排行即校园兴趣生态。注意App 18 的排行是兴趣排行榜编程/动漫/篮球/音乐而 App 13-17 是商品/场地/分类排行榜——排行对象 业务核心对象社交 App 排行兴趣电商排商品。**排行组件模板复用、排行数据按业务换**是本系列排行页的通用模式。十一、首页与消息页的人物闭环App 18 有一个前几代没有的跨页人物闭环首页推荐的 4 个人小明/小美/小华/小雪→ 消息页的 4 个聊天对象同名同头像首页推荐卡小明 92% 匹配度 打招呼按钮 → 点击打招呼 → 消息页小明聊天未读 2 条 → 进入聊天 → 好友关系建立 → 我的页好友 56 / 互动 128 统计推荐 → 打招呼 → 聊天 → 好友是社交 App 的完整用户旅程——App 18 用同名同头像在 3 个页面暗示这条旅程首页推荐的人、消息页可聊天的人、我的页统计的人。跨页人物一致让 demo 的社交生态自洽可信。真实项目的实现用户模型UserProfile全局共享——首页推荐列表、消息页会话列表、我的页好友统计都引用同一批用户数据单一数据源原则。十二、总结App 18 首页解析完毕。匹配度环形进度ProgressType.Ring 在线状态点 兴趣标签 跳过/打招呼双按钮 涨跌排行是五大亮点。独立搜索栏区别于系列内嵌搜索和粉红社交调性让首页区别于 App 13-17。

相关新闻