news 2026/10/3 6:11:32

鸿蒙原生应用 ArkUI 声明式实战:通讯录我的页 —— 渐变卡 + 悬浮统计 + Toggle 隐私卡组合技

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙原生应用 ArkUI 声明式实战:通讯录我的页 —— 渐变卡 + 悬浮统计 + Toggle 隐私卡组合技

鸿蒙原生应用 ArkUI 声明式实战:通讯录我的页 —— 渐变卡 + 悬浮统计 + Toggle 隐私卡组合技

App 46「班级通讯录」我的页(ProfileTab),主题色#0984E3蓝色(blue),4 个 Tab 分别为首页(🏠)、通讯录(👥)、班级(📋)、我的(👤)。我的页采用"UserCard + 统计行 + 隐私卡 + 菜单 + 关于"五区布局——蓝色渐变 UserCard(📇 64×64 半透明名片头像 + "通讯录达人"18 号加粗 + “计科2022级 · 张娜”)+三列悬浮统计卡(45 班级成员 / 12 常用联系人 / 8 最近通话,负 margin 上浮)+隐私设置卡(“公开手机号” + “开启后班级同学可查看你的号码” + Toggle 开关,蓝色 selectedColor)+5 行菜单(👤 个人资料 / 📞 通话记录 / 🔒 隐私设置 / 💬 消息通知 / ⚙️ 通用设置)+底部关于区(班级通讯录 Version 1.0.0)。本篇基于46-class-contacts/entry/src/main/ets/pages/ProfileTab.ets(共 105 行)逐段拆解,附 4 张实机截图。

一、整体结构:五区"UserCard + 统计 + 隐私 + 菜单 + 关于"布局

我的页是五个 @Builder 块纵向堆叠的"个人中心"标准范式:

build() { Column() { Scroll() { Column() { this.UserCard() this.StatRow() this.PrivacyCard() this.MenuList() this.About() } .width('100%') .padding({ bottom: D.pad + this.safeBottom + 20 }) } .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top) } .width('100%').height('100%').backgroundColor(C.bg) }

5 块结构:

  1. UserCard— 蓝色渐变品牌区,展示通讯录达人身份与班级身份
  2. StatRow— 三列悬浮统计卡(45 班级成员 / 12 常用联系人 / 8 最近通话)
  3. PrivacyCard—系列首个隐私开关卡(公开手机号 Toggle)
  4. MenuList— 5 行功能菜单
  5. About— 底部版本信息收尾

与 App 39-45 我的页同构的"头图 + 悬浮卡 + 菜单 + 版本"范式 +系列首次的隐私开关卡——蓝色主题、通讯录业务指标、隐私可见性设置是本页的三大特色。

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

二、UserCard:蓝色渐变头图 + 📇 名片头像

UserCard() { Row({ space: 14 }) { Row() { Text('📇').fontSize(32) } .width(64).height(64).backgroundColor('#33FFFFFF').borderRadius(32).justifyContent(FlexAlign.Center) Column({ space: 5 }) { Text('通讯录达人').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#FFFFFF') Text('计科2022级 · 张娜').fontSize(12).fontColor('#FFFFFF').opacity(0.85) }.alignItems(HorizontalAlign.Start).layoutWeight(1) } .width('100%') .padding({ top: this.safeTop + 30, left: D.pad, right: D.pad, bottom: 44 }) .linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] }) }

技术拆解:

  1. 渐变头图:linearGradient从#0984E3蓝渐变到#4DA3F0浅蓝——与首页班级卡同款蓝色渐变,品牌统一。
  2. 📇 名片头像:64×64 半透明圆底 + 32 号 📇——与 Tab 图标(🏠 不同)、副标题(📇)呼应,"名片/通讯录"的符号语义。
  3. 昵称"通讯录达人":达人定位——“联系人多的达人”(45 人班级 + 12 常用联系人),通讯录产品的"人脉达人"人设。
  4. 副标题含姓名:“计科2022级 · 张娜”——首次在个人中心展示本人姓名(张娜 = 通讯录页第一位成员),班级 + 姓名双重身份,用户在自己的通讯录主页"实名可见"。
  5. 底部 44 padding + 安全区:为悬浮统计卡预留空间、顶部避让状态栏。

三、StatRow:三列悬浮统计卡

StatRow() { Row() { ForEach(this.stats, (s: StatItem) => { Column({ space: 4 }) { Text(s.value).fontSize(18).fontWeight(FontWeight.Bold).fontColor(C.text) Text(s.label).fontSize(11).fontColor(C.textDim) }.layoutWeight(1) }, (s: StatItem) => s.label) } .width('92%').padding({ top: 14, bottom: 14 }) .backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }).margin({ top: -24 }) }

统计数据(15-19 行):45 班级成员 / 12 常用联系人 / 8 最近通话——三列,指标完全贴合通讯录业务:“班级成员”(班级规模)、“常用联系人”(个人联系圈)、“最近通话”(近期互动)——规模 + 人脉 + 活动的三元统计是通讯录产品的标准数据模型。

技术要点:

  1. 负 margin 悬浮:.margin({ top: -24 })上移叠加在渐变区下缘——系列标志性手法。
  2. 三列等分:三个 ColumnlayoutWeight(1)自动三等分,18 号数字 + 11 号标签。
  3. 92% 宽度:左右留 4% 呼吸边距。
  4. key:s.label(班级成员/常用联系人/最近通话,天然唯一)。

数据自洽:45 班级成员 ↔ 首页"45 名成员" ↔ 班级页"总人数 45";12 常用联系人 ↔ 通讯录页展示成员(5 位)+ 首页核心角色(3 位)+ 其他常用;8 最近通话 ↔ 📞 呼叫动作的累计——数字处处有出处。

四、PrivacyCard:隐私设置卡(系列首次隐私开关)

PrivacyCard() { Row() { Column({ space: 2 }) { Text('公开手机号').fontSize(14).fontColor(C.text) Text('开启后班级同学可查看你的号码').fontSize(11).fontColor(C.textDim) }.alignItems(HorizontalAlign.Start).layoutWeight(1) Toggle({ type: ToggleType.Switch, isOn: this.publicPhone }) .selectedColor(C.primary) .onChange((v: boolean) => { this.publicPhone = v; }) } .width('92%').padding(16).margin({ top: 14 }).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) }

技术拆解:

  1. 左文右开关:左侧双行文字(14 号"公开手机号" + 11 号说明"开启后班级同学可查看你的号码"),layoutWeight(1)撑开,右侧Toggle开关。
  2. Toggle 开关:Toggle({ type: ToggleType.Switch, isOn: this.publicPhone })+selectedColor(C.primary)蓝色开启态 +onChange写入@State publicPhone——与 App 42 树洞投稿"匿名开关"同款组件,但语义不同:树洞控"是否匿名"、本页控"号码是否公开"。
  3. 默认开启:publicPhone: boolean = true——通讯录的默认逻辑是"号码公开"(班级通讯录的用途就是互查号码),用户可手动关闭。
  4. 隐私说明文案:“开启后班级同学可查看你的号码”——一句话说清开关的后果,用户基于明确信息做隐私决策(可信隐私设计的核心)。
  5. 隐私与呼叫的联动:关闭后他人通讯录中不显示号码(📞 呼叫不可用或转站内消息)——开关状态驱动全 App 的可见性。

五、MenuList:5 行菜单 + Divider 条件分隔

MenuList() { Column() { ForEach(this.menus, (m: MenuItem, idx: number) => { Row({ space: 12 }) { Text(m.emoji).fontSize(18) Text(m.title).fontSize(14).fontColor(C.text).layoutWeight(1) Text('>').fontSize(14).fontColor(C.textDim) } .width('100%').padding({ left: 14, right: 14, top: 14, bottom: 14 }) .onClick(() => { promptAction.showToast({ message: m.title }); }) if (idx < this.menus.length - 1) { Divider().color(C.stroke).strokeWidth(0.5) } }, (m: MenuItem) => m.title) } .width('92%').margin({ top: 14 }).backgroundColor(C.card).borderRadius(D.rMd).border({ width: 1, color: C.stroke }) }

5 个菜单项(22-28 行):👤 个人资料 / 📞 通话记录 / 🔒 隐私设置 / 💬 消息通知 / ⚙️ 通用设置。

菜单语义分析:

  1. 👤 个人资料:自己的资料编辑(姓名/学号/头像/手机号)——对应 UserCard 的身份信息。
  2. 📞 通话记录:呼叫历史(谁、何时、时长)——对应统计"8 最近通话"。
  3. 🔒 隐私设置:隐私开关的完整页(公开手机号/在线状态可见性/位置)——PrivacyCard 是概览、本菜单是完整设置。
  4. 💬 消息通知:公告/消息推送开关——对应班级公告的推送触达。
  5. ⚙️ 通用设置:关于、缓存、账号等。

实现细节:三栏行(emoji + 标题 + “>”)、ForEachindex 判断最后一行不加 Divider、整行可点 Toast、92% 宽卡片——系列标准菜单卡。margin({ top: 14 })与隐私卡保持间距。

六、About:版本信息收尾

About() { Column({ space: 4 }) { Text('班级通讯录').fontSize(12).fontColor(C.textDim) Text('Version 1.0.0').fontSize(11).fontColor(C.textDim).opacity(0.7) }.width('100%').margin({ top: 24 }) }

12 号浅灰应用名 + 11 号更浅版本号(opacity(0.7)),margin({ top: 24 })与菜单卡拉开距离——系列统一收尾。

七、跨页数据自洽:我的页 = 通讯录达人档案

我的页每个元素都能在其他页面找到呼应:

  • “张娜”↔ 通讯录页第一位成员(👨‍🎓 张娜)——本人即通讯录中的一员,实名个人中心(不同于匿名 App)。
  • “计科2022级”↔ 首页班级卡 ↔ 班级页统计卡——班级名三页统一。
  • “45 班级成员”↔ 首页"45 名成员" ↔ 班级页"总人数 45"——45 三处一致。
  • "公开手机号"开关↔ 通讯录的 📞 呼叫——开关状态决定他人能否呼叫本人。
  • "📞 通话记录"菜单↔ 首页/通讯录的 📞 呼叫动作——呼叫历史在此沉淀。

八、实机截图与交互演示

本节结合 4 张实机截图,逐张还原我的页的视觉效果与交互过程。

1. 我的页首屏:蓝色渐变 + 统计 + 隐私卡

第一张截图是我的页默认首屏:顶部蓝色渐变 UserCard——📇 半透明名片头像、右侧"通讯录达人"加粗白字与"计科2022级 · 张娜"(姓名首次出现在个人中心);下方白色统计卡以负边距悬浮在渐变区下缘,三列数字(45 班级成员 / 12 常用联系人 / 8 最近通话)等分排布;再往下是隐私设置卡"公开手机号"(蓝色开启 Toggle + 说明"开启后班级同学可查看你的号码")与菜单第一行"👤 个人资料"。蓝色渐变 + 隐私开关是本页的两大特色。

2. 点击"个人资料":弹出 Toast

第二张截图是点击菜单第一行"👤 个人资料"后的反馈:弹出"个人资料"Toast。菜单整行可点(emoji、标题、箭头任意位置均触发),"个人资料"是本人信息的编辑入口——对应 UserCard 的"计科2022级 · 张娜"身份信息。

3. 点击"通话记录":弹出 Toast

第三张截图是点击菜单第二行"📞 通话记录"后的反馈:弹出"通话记录"Toast。"通话记录"对应统计"8 最近通话"的明细——与首页/通讯录的 📞 呼叫动作衔接,呼叫历史(谁、何时、时长)在此查看,是通讯录"联系闭环"的记录层。

4. 我的页完整视图:隐私卡 + 菜单 + 版本

第四张截图是我的页完整视图:隐私设置卡(公开手机号 Toggle)、五个菜单(👤 个人资料 / 📞 通话记录 / 🔒 隐私设置 / 💬 消息通知 / ⚙️ 通用设置)、底部"班级通讯录 / Version 1.0.0"全部可见。从渐变头图到版本号,五区块在单屏内完整呈现。

九、扩展思考:通讯录的隐私与信任设计

隐私开关卡是通讯录产品的核心信任设计,完整体系值得展开:

  1. 号码可见性的粒度:公开手机号(当前开关)之上可细分"仅班委可见/全班可见/仅老师可见"——按角色分级控制,隐私粒度更精细。
  2. 在线状态的隐私:在线状态是个人数据(谁看到你在线)——隐私设置应有"在线状态可见性"开关(隐身模式),与号码可见性并列。
  3. 位置与呼叫权限:若支持"附近同学"或呼叫,需系统权限(电话/位置)——权限申请需说明用途(“用于拨打同学电话”),符合最小化原则。
  4. 隐私的默认值:号码默认公开(通讯录用途)但应有明显提醒(首次开启的弹窗说明)——默认公开 + 明示告知是通讯录隐私的平衡。
  5. 被遗忘权:转班/毕业时可"退出班级通讯录"(数据移除)——通讯录个人数据的删除权,产品合规底线。

十、扩展思考:通讯录产品的呼叫与消息能力

📞 呼叫是通讯录的核心动作,完整的能力矩阵值得展开:

  1. 呼叫能力:📞 调起系统拨号(@ohos.telephony)拨打成员号码——号码来自通讯录数据(受隐私开关控制),呼叫前确认号码可见。
  2. 通话记录:我的页"📞 通话记录"展示呼叫历史(对方/时间/时长)——@ohos.telephony的通话记录读取或本地记录。
  3. 消息能力:通讯录可扩展"站内消息"(私聊同学,App 38 交流页模式)——隐私关闭号码时,消息成为替代联系方式。
  4. 班级群聊:首页快捷入口"💬 群聊"——班级全员群(公告的讨论区),与通讯录成员体系打通。
  5. 呼叫与状态的联动:在线状态(绿点)提示"此刻可联系"、离线提示"最后在线时间"——状态驱动呼叫决策,减少无效呼叫。

十一、开发者视角:我的页的调试与验证技巧

  1. 负 margin 叠层:统计卡margin({ top: -24 })悬浮,构建顺序(UserCard 先、StatRow 后)决定 StatRow 在上层——调整构建顺序需配合zIndex(系列同款坑)。
  2. Toggle 状态与全局联动:publicPhone开关状态应影响通讯录的号码可见性(他人视角)——Demo 开关独立,产品化需全局状态(AppStorage)驱动,验证开关与呼叫可用性的联动。
  3. 统计数字的跨页核对:45/12/8 与首页(45 名成员)、班级页(45 人)、通讯录页(5 位展示)的核对——"数字处处有出处"的系列标准。
  4. 姓名的一致性:"张娜"在 UserCard 与通讯录页第一位成员——修改任一页需同步(同一用户数据源)。
  5. 菜单 key 长期方案:新增菜单项改用 id 作 key(当前m.title5 项内唯一)——系列标准建议。

十二、FAQ 与一句话总结

Q1:为什么我的页首次显示真实姓名(张娜)?
通讯录是"实名产品"(班级成员互查联系方式需要实名)——与 App 41/42 的匿名不同,通讯录的核心是"真实可靠的联系",实名是产品的信任基础,UserCard"计科2022级 · 张娜"即实名身份。

Q2:"公开手机号"开关是做什么的?
控制自己的手机号对班级同学的可见性——开启(默认)他人可在通讯录看到并呼叫号码、关闭则隐藏号码(仅站内消息)——隐私开关让用户掌握自己信息的可见权,是通讯录的信任设计核心。

Q3:45 班级成员和通讯录的 5 位成员什么关系?
45 是全班总数(班级页统计 + 首页规模),5 位是通讯录页当前展示的成员样例——"展示样例 vs 总人数"的口径与系列惯例一致,真实产品滚动展示全部 45 人。

Q4:关闭公开手机号后还能被呼叫吗?
不能直接呼叫(号码不可见)——他人可通过站内消息联系你;产品化后"隐私开关 → 号码可见性 → 呼叫可用性"三级联动,关闭即保护。

一句话总结:我的页以 105 行代码完成了通讯录达人的个人中心——蓝色渐变头图配 📇 名片头像、"计科2022级 · 张娜"的实名身份、“45 成员 / 12 联系人 / 8 通话"的人脉统计、首个隐私开关卡(公开手机号 Toggle)、5 菜单覆盖"资料/通话/隐私/消息/设置”。实名身份 + 隐私可见性控制是本页的双核,让通讯录"可靠联系"与"隐私可控"两大诉求在个人中心得到平衡。

十三、系列横向对比:隐私设置的三级形态

App 46 的隐私开关卡是系列隐私设计的第三级,与前代对比可看清演进:

隐私形态代表控制对象默认值
匿名开关App 42 树洞发布是否匿名默认匿名
匿名声明App 41 表白墙常驻匿名承诺无条件匿名
可见性开关App 46 通讯录号码对同学可见默认公开

演进逻辑:树洞的隐私是"隐藏身份"(匿名,防止被认出)、通讯录的隐私是"控制可见"(号码,选择谁能看到)——匿名是"我不说我是谁"、可见性是"我的信息对谁开放",两类隐私语义不同:匿名产品保护"表达者身份"、实名产品保护"信息可见范围"。App 46 的"公开手机号"开关是系列首次"可见性控制"——用户掌控自己信息的开放程度,这是实名通讯录的信任设计核心(与 App 42 的匿名开关并列,构成隐私设计的两个方向:隐藏 vs 开放)。

开关的默认值哲学:树洞默认匿名(匿名是产品灵魂,无需选择)、通讯录默认公开(通讯录的用途是互查号码,公开是默认)——默认值反映产品核心价值:树洞卖"匿名安全感"所以默认匿、通讯录卖"可靠联系"所以默认公开,两个开关的默认取向都服务于产品定位。

十四、扩展思考:通讯录的完整产品能力矩阵

我的页之外,通讯录产品的能力矩阵值得完整勾勒:

  1. 联系层:呼叫(📞 拨号)、消息(站内私聊)、群聊(班级群)——联系是通讯录的"出口",三种联系方式覆盖"电话/私聊/群聊"。
  2. 组织层:班级统计(45 人)、公告(事务通知)、相册(集体记忆)——组织是通讯录的"内容",班级页承载。
  3. 身份层:个人资料(姓名/学号/号码)、在线状态(此刻可联系)、隐私开关(信息可见性)——身份是通讯录的"底座",我的页承载。
  4. 数据层:通话记录(呼叫历史)、常用联系人(高频圈)、最近通话(近期互动)——数据是通讯录的"足迹",我的页统计承载。
  5. 联动闭环:联系(呼叫)→ 记录(通话记录)→ 沉淀(常用联系人)——通讯录的三层能力形成"联系 → 记录 → 沉淀"的完整闭环,我的页正是这个闭环的终端。

十五、开发者视角:我的页的调试与验证技巧

  1. 负 margin 叠层:统计卡margin({ top: -24 })悬浮,构建顺序(UserCard 先、StatRow 后)决定 StatRow 在上层——调整构建顺序需配合zIndex(系列同款坑)。
  2. Toggle 状态与全局联动:publicPhone开关状态应影响通讯录的号码可见性(他人视角)——Demo 开关独立,产品化需全局状态(AppStorage)驱动,验证开关与呼叫可用性的联动。
  3. 统计数字的跨页核对:45/12/8 与首页(45 名成员)、班级页(45 人)、通讯录页(5 位展示)的核对——"数字处处有出处"的系列标准。
  4. 姓名的一致性:"张娜"在 UserCard 与通讯录页第一位成员——修改任一页需同步(同一用户数据源)。
  5. 菜单 key 长期方案:新增菜单项改用 id 作 key(当前m.title5 项内唯一)——系列标准建议。
  6. Toggle 的语义色:selectedColor(C.primary)蓝色开启态——与树洞(紫)、本页(蓝)的开关色调跟随主题色,验证主题色变化时开关同步(系列主题色驱动的惯例)。

十六、FAQ 与一句话总结

Q6:隐私开关影响哪些地方?
"公开手机号"关闭后——通讯录成员详情不显示号码、首页/通讯录的 📞 呼叫不可用(转站内消息)、他人无法直接拨号——一处开关、全链路生效,产品化用全局状态驱动。

Q7:我的页为什么展示真实姓名而不是昵称?
通讯录是实名产品——班级互查联系方式的前提是实名可信,UserCard"计科2022级 · 张娜"即实名身份(与匿名 App 41/42 形成对比);若用户想隐藏姓名,可设"昵称显示"(实名数据、昵称展示)。

Q8:最近通话 8 次是怎么统计的?
📞 呼叫动作的累计(每次呼叫 +1)——产品化后从通话记录表统计"近 30 天呼叫次数",与"📞 通话记录"菜单明细联动。

Q9:常用联系人 12 人是自动的还是手动的?
可自动(按呼叫频率 Top12)+ 手动置顶——自动学习 + 手动控制结合,我的页"12 常用联系人"是常用圈的数据沉淀。

Q10:本页与系列其他 App 个人中心的隐私设计有什么不同?
其他 App 的隐私在"设置"菜单里(App 41/42 的隐私设置项),本页把隐私独立成卡(PrivacyCard 置顶展示)——因为"号码可见性"是通讯录的高频隐私(用户常调),需要常驻可见;低相关性的隐私进菜单,高频隐私独立成卡,隐私的层级跟随使用频率。这些 FAQ 与前面的拆解共同构成本页的完整解析。

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

JavaScript+Canvas+GSAP+FFmpeg:代码生成视频全链路实战

1. 从一段“会动的画面”说起&#xff1a;这个项目到底在做什么第一次看到“Claude Opus 5.5 是怎么做出视频的”这个标题&#xff0c;我脑子里冒出来的第一个念头不是“AI 直接生成视频”&#xff0c;而是——它大概率是用代码把视频“拼”出来的。原因很简单&#xff0c;真正…

作者头像 李华
网站建设 2026/10/3 6:07:22

从零搭建AI工程能力:数据管道与评估体系先行,避开调包侠陷阱

1. 从零搭建AI工程能力&#xff1a;为什么我劝你别一上来就啃论文这两年“AI工程”这个词被炒得火热&#xff0c;招聘网站上挂着“AI工程师”的岗位薪资一个比一个高&#xff0c;培训班广告铺天盖地&#xff0c;仿佛只要学了几个框架调用、跑通了几个Demo&#xff0c;就能顺利上…

作者头像 李华
网站建设 2026/10/3 6:03:37

Paperclip本地AI智能体开发全栈指南:OpenClaw+Claude Code+React+Node.js

1. 项目概述&#xff1a;Paperclip 不是回形针&#xff0c;而是一个被严重误读的 AI 工具链代号 “Paperclip”这个词在中文技术社区里最近变得异常魔幻——它既不是 Office 里的那个金属弯钩&#xff0c;也不是某款小众 UI 组件库&#xff0c;更不是某个新出的 Node.js 包名。…

作者头像 李华
网站建设 2026/10/3 6:02:55

AI能力封装协议skills:YAML声明式技能管理与Claude集成实战

1. 项目概述&#xff1a;从“skills”这个词开始&#xff0c;我们到底在谈什么&#xff1f;“skills”这个词最近在技术圈里反复刷屏&#xff0c;但很多人点开搜索结果后反而更迷糊了——它既不是某个具体软件&#xff0c;也不是一门编程语言&#xff0c;更不是某家公司的产品。…

作者头像 李华
网站建设 2026/10/3 6:01:13

开源AI工作站openrig搭建指南:从硬件选型到大模型微调全流程

"openrig"这个名字&#xff0c;第一次看到的时候我就觉得有点意思。rig这词在机房和玩硬件的人嘴里太常用了&#xff0c;指的就是那台专门用来跑活儿的机器——可以是渲染农场里的一张卡&#xff0c;也可以是工位上嗡嗡作响的深度学习工作站。加上open这个前缀&#…

作者头像 李华