HarmonyOS 校园应用系列之HarmonyOS ArkTS实战:水电缴费我的页 —— 负边距上浮统计与成就墙锁定态组合技
HarmonyOS 校园应用系列之HarmonyOS ArkTS实战:水电缴费我的页 —— 负边距上浮统计与成就墙锁定态组合技
应用背景:10 水电缴费个人中心页(ProfileTab.ets,289 行)展示用户画像、缴费统计、成就体系与活跃度。本文聚焦 UserInfo 渐变资料卡、负 Margin 统计卡、成就墙锁定态、菜单列表 四大模块。

一、页面整体结构
// ProfileTab.ets — 页面根结构
Column() {
Scroll() {
Column({ space: 0 }) {
this.UserInfo()
this.StatGrid()
this.AchievementWall()
this.WeekChart()
this.MenuList()
this.AboutInfo()
}
.width('100%')
.padding({ bottom: this.safeBottom + 20 })
}
.layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top)
}
.width('100%').height('100%').backgroundColor(C.bg)
本页没有独立 Header——渐变 UserInfo 卡直接顶到屏幕最上方充当头部(内部自行处理 safeTop),滚动区 Column({ space: 0 }) 纵向排布 6 个模块,各模块自带左右 D.pad margin。

二、UserInfo 渐变资料卡
2.1 布局与签到交互
// UserInfo — 个人资料卡
@Builder
UserInfo() {
Column({ space: 14 }) {
Row({ space: 14 }) {
Column() {
Text('👤').fontSize(34)
}
.width(64).height(64)
.backgroundColor('#33FFFFFF').borderRadius(32)
.justifyContent(FlexAlign.Center)
Column({ space: 4 }) {
Row({ space: 8 }) {
Text('张同学').fontSize(18).fontWeight(FontWeight.Bold).fontColor('#FFFFFF')
Text('Lv.' + this.level).fontSize(11).fontColor('#FFFFFF')
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
.backgroundColor('#33FFFFFF').borderRadius(10)
}
Text('梅园 6 栋 302 室').fontSize(12).fontColor('#FFFFFF').opacity(0.85)
}
.alignItems(HorizontalAlign.Start).layoutWeight(1)
Column({ space: 4 }) {
Text(this.checked ? '✓ 已签到' : '签到').fontSize(12).fontColor('#FFFFFF')
.padding({ left: 12, right: 12, top: 6, bottom: 6 })
.backgroundColor(this.checked ? '#33FFFFFF' : '#FFFFFF')
.fontColor(this.checked ? '#FFFFFF' : C.primary)
.borderRadius(16)
.onClick(() => {
this.checked = !this.checked;
if (this.checked) { this.exp = Math.min(this.exp + 10, 100); }
promptAction.showToast({ message: this.checked ? '签到成功 +10 经验' : '已取消' });
})
}
.alignItems(HorizontalAlign.End)
}
.width('100%')
Column({ space: 6 }) {
Row() {
Text('经验值').fontSize(11).fontColor('#FFFFFF').opacity(0.8)
Blank()
Text(this.exp + ' / 100').fontSize(11).fontColor('#FFFFFF').opacity(0.8)
}
.width('100%')
Progress({ value: this.exp, total: 100 }).color('#FFFFFF').backgroundColor('#33FFFFFF').width('100%')
}
.width('100%')
}
.width('100%')
.padding({ left: D.pad, right: D.pad, top: this.safeTop + 30, bottom: 24 })
.linearGradient({ angle: 135, colors: [[C.primary, 0.0], [C.accent, 1.0]] })
}
渐变卡无 Stack 分层,纯 Column + linearGradient(135° 主色→亮青)实现。三个细节值得注意:
- 头像:64vp 圆形(
borderRadius(32)),底色是 20% 半透明白#33FFFFFF而非纯白,与渐变底融合更自然 - 等级徽标:
'Lv.' + this.level(Lv.5),白字 + 半透明白底胶囊 - 签到是 Text 而非 Button:三元表达式同时切换文案(签到 ↔ ✓ 已签到)、底色(白 ↔ 半透明白)、字色(主色 ↔ 白);点击翻转
checked,签到时Math.min(this.exp + 10, 100)经验 +10 封顶 100,toast 反馈"签到成功 +10 经验"
2.2 经验进度条
// 经验条(UserInfo 内部)
Column({ space: 6 }) {
Row() {
Text('经验值').fontSize(11).fontColor('#FFFFFF').opacity(0.8)
Blank()
Text(this.exp + ' / 100').fontSize(11).fontColor('#FFFFFF').opacity(0.8)
}
.width('100%')
Progress({ value: this.exp, total: 100 }).color('#FFFFFF').backgroundColor('#33FFFFFF').width('100%')
}
.width('100%')
系统 Progress 组件:白色填充 + 20% 透明白轨道,exp 初始 68,签到 +10 且封顶 100。

三、StatGrid 四维统计
// StatGrid — 统计卡
@Builder
StatGrid() {
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).alignItems(HorizontalAlign.Center)
}, (s: StatItem) => s.label)
}
.width('90%')
.padding({ top: 16, bottom: 16 })
.backgroundColor(C.card)
.borderRadius(D.rLg)
.border({ width: 1, color: C.stroke })
.margin({ top: -28, left: D.pad, right: D.pad })
.shadow({ radius: 12, color: '#10000000', offsetX: 0, offsetY: 4 })
}
负 Margin 上浮:.margin({ top: -28 }) 让白卡向上叠进渐变卡底部,配合 shadow 投影强化悬浮层次。四维统计:缴费次数(24) / 累计金额(¥478) / 优惠券(12) / 绑定房间(3),layoutWeight(1) 四等分、无分隔线。
// stats 数据定义
private stats: StatItem[] = [
{ value: '24', label: '缴费次数' },
{ value: '¥478', label: '累计金额' },
{ value: '12', label: '优惠券' },
{ value: '3', label: '绑定房间' }
]
四、AchievementWall 成就墙
4.1 数据模型
// 成就数据
private badges: BadgeItem[] = [
{ emoji: '🏆', name: '缴费达人', locked: false },
{ emoji: '🌱', name: '节能先锋', locked: false },
{ emoji: '⚡', name: '闪电充值', locked: false },
{ emoji: '💧', name: '节水卫士', locked: false },
{ emoji: '🔥', name: '连续签到', locked: true },
{ emoji: '👑', name: '年度冠军', locked: true }
]
BadgeItem 仅三字段(emoji/name/locked),6 个成就按 30% 宽度三列两行排布:前 4 个已解锁,后 2 个锁定。
4.2 锁定态差异化渲染
// AchievementWall — 成就墙
@Builder
AchievementWall() {
Column({ space: 12 }) {
Text('成就墙').fontSize(16).fontWeight(FontWeight.Bold).fontColor(C.text).width('100%')
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.SpaceBetween }) {
ForEach(this.badges, (b: BadgeItem) => {
Column({ space: 6 }) {
Row() {
Text(b.emoji).fontSize(28).opacity(b.locked ? 0.4 : 1)
}
.width(52).height(52)
.backgroundColor(b.locked ? C.cardSoft : C.primarySoft)
.borderRadius(26)
.justifyContent(FlexAlign.Center)
Text(b.name).fontSize(10).fontColor(b.locked ? C.textDim : C.textSub)
Text(b.locked ? '未解锁' : '已获得').fontSize(9).fontColor(b.locked ? C.textDim : C.primary)
}
.width('30%')
.padding({ top: 10, bottom: 10 })
.alignItems(HorizontalAlign.Center)
.onClick(() => {
promptAction.showToast({ message: b.locked ? b.name + '(未解锁)' : b.name + '(已获得)' });
})
}, (b: BadgeItem) => b.name)
}
.width('100%')
}
.width('100%')
.padding(14)
.backgroundColor(C.card)
.borderRadius(D.rLg)
.border({ width: 1, color: C.stroke })
.margin({ top: 14, left: D.pad, right: D.pad })
}
锁定态双重区分(无虚线边框):图标 opacity(0.4) 半透明 + 圆形底色由浅青 C.primarySoft 换浅灰 C.cardSoft;第三行状态文字"未解锁"灰 / "已获得"主色。点击 toast 带解锁状态后缀。

五、WeekChart 缴费活跃度
// WeekChart — 活跃度图表
@Builder
WeekChart() {
Column({ space: 12 }) {
Row() {
Text('本周缴费活跃度').fontSize(15).fontWeight(FontWeight.Bold).fontColor(C.text)
Blank()
Text('连续 5 天').fontSize(12).fontColor(C.primary)
}
.width('100%')
Row({ space: 6 }) {
ForEach(this.weekBars, (w: WeekBar) => {
Column({ space: 6 }) {
Column() {
Column()
.width('100%')
.height(Math.floor(w.value / this.maxBar * 70))
.backgroundColor(C.primary)
.borderRadius(4)
}
.width('100%').height(70)
Text(w.day).fontSize(11).fontColor(C.textDim)
}
.layoutWeight(1).alignItems(HorizontalAlign.Center)
}, (w: WeekBar) => w.day)
}
.width('100%')
}
.width('100%')
.padding(14)
.backgroundColor(C.card)
.borderRadius(D.rLg)
.border({ width: 1, color: C.stroke })
.margin({ top: 14, left: D.pad, right: D.pad })
}
与首页 WeekChart 同构但轨道高 70(首页 80):Math.floor(w.value / this.maxBar * 70) 归一化柱高,maxBar 同为 90,数据同为 45/72/38/90/55/68/42。柱体 width('100%') 由 layoutWeight(1) 七等分自适应,标题行右侧"连续 5 天"主色激励文案。

六、MenuList 菜单列表
// MenuList — 菜单列表
@Builder
MenuList() {
Column({ space: 0 }) {
ForEach(this.menus, (m: MenuItem) => {
Row({ space: 12 }) {
Row() {
Text(m.icon).fontSize(20)
}
.width(36).height(36)
.backgroundColor(C.cardSoft).borderRadius(D.rSm)
.justifyContent(FlexAlign.Center)
Text(m.label).fontSize(14).fontColor(C.text).layoutWeight(1)
if (m.badge.length > 0) {
Text(m.badge).fontSize(11).fontColor(C.danger)
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
.backgroundColor(C.primarySoft).borderRadius(8)
}
Text('>').fontSize(14).fontColor(C.textDim)
}
.width('100%')
.padding({ left: 14, right: 14, top: 12, bottom: 12 })
.onClick(() => { promptAction.showToast({ message: m.action }); })
if (m.label !== '帮助反馈') {
Divider().color(C.stroke).strokeWidth(0.5).margin({ left: 62 })
}
}, (m: MenuItem) => m.label)
}
.width('100%')
.backgroundColor(C.card)
.borderRadius(D.rLg)
.border({ width: 1, color: C.stroke })
.margin({ top: 14, left: D.pad, right: D.pad })
}
菜单数据与交互:
// 菜单数据
private menus: MenuItem[] = [
{ icon: '💳', label: '我的钱包', badge: '¥86', action: '钱包余额' },
{ icon: '🎟️', label: '优惠券', badge: '3张', action: '查看优惠券' },
{ icon: '🏠', label: '房屋管理', badge: '', action: '管理房屋' },
{ icon: '🔔', label: '消息通知', badge: '2', action: '消息通知' },
{ icon: '🛡️', label: '安全中心', badge: '', action: '安全设置' },
{ icon: '❓', label: '帮助反馈', badge: '', action: '帮助与反馈' }
]
action是 string(toast 文案)而非回调函数,点击统一promptAction.showToast({ message: m.action })- 徽标条件渲染
if (m.badge.length > 0):红字浅青底(C.danger字 +C.primarySoft底) - 分割线
Divider左缩进 62vp 对齐文字,末项"帮助反馈"后不渲染
七、AboutInfo 版本信息
// AboutInfo — 版本信息
@Builder
AboutInfo() {
Column({ space: 6 }) {
Text('水电缴费 v1.0.0').fontSize(12).fontColor(C.textDim)
Text('Powered by HarmonyOS 6.0+ · ArkTS').fontSize(11).fontColor(C.textDim)
Text('© 2025 校园智慧生活').fontSize(10).fontColor(C.textDim)
}
.width('100%')
.padding({ top: 20, bottom: 10 })
.alignItems(HorizontalAlign.Center)
}
页脚三行居中灰字:版本号 v1.0.0 / 技术栈标识 Powered by HarmonyOS 6.0+ / 版权信息,字号 12→11→10 递减。

八、本章小结
| 组件 | 核心技术 | 学习价值 |
|---|---|---|
| UserInfo | linearGradient + Text 签到切换 | 个人中心标准头部 |
| StatGrid | margin(-28) 上浮 + shadow | 卡片层次感设计 |
| AchievementWall | opacity + 底色锁定态 | 游戏化成就系统 |
| WeekChart | Math.floor 归一化柱高 | 数据可视化一致性 |
| MenuList | string action + 条件徽标 | 功能导航通用方案 |
| AboutInfo | 三行递减页脚 | 版本信息规范 |
UserInfo 渐变资料卡 最具学习价值——签到 Text 三元切换文案/底色/字色,Math.min(exp + 10, 100) 一行完成经验值封顶,配合负 Margin 统计卡上浮构建层次感。
更多推荐




所有评论(0)