HarmonyOS应用开发实战:萌宠日记 - 成长记录卡片网格布局
前言
在萌宠日记的宠物档案页中,成长记录卡片以网格布局展示宠物在幼年、6个月、1岁、2岁四个阶段的照片和标签。每个阶段使用等宽列均匀分布,配合圆形占位图和文字标签,形成清晰的成长轨迹。
本文将从萌宠日记的成长记录卡片实现出发,深入解析网格布局的 layoutWeight 等分机制、占位图设计、卡片结构以及数据驱动的渲染方式。
一、成长记录卡片整体设计
1.1 卡片结构
┌─────────────────────────────────────┐ │ 成长记录 │ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ │ │ 🐶 │ │ 🐶 │ │ 🐶 │ │ 🐶 ││ │ │ │ │ │ │ │ │ ││ │ └──────┘ └──────┘ └──────┘ └──────┘│ │ 幼年 6个月 1岁 2岁 │ └─────────────────────────────────────┘1.2 完整代码
// PetProfilePage.ets — 成长记录卡片 Column({ space: 12 }) { // 标题 Text('成长记录') .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor('#333333') .width('100%') // 网格布局 Row({ space: 8 }) { ForEach(['幼年', '6个月', '1岁', '2岁'], (label: string) => { Column({ space: 4 }) { // 占位图 Column() { Text('🐶') .fontSize(24) } .width(64) .height(64) .backgroundColor('#FFF3E0') .borderRadius(12) .justifyContent(FlexAlign.Center) // 标签 Text(label) .fontSize(11) .fontColor('#666666') } .layoutWeight(1) // 等宽列 .alignItems(HorizontalAlign.Center) }) } .width('100%') } .width('100%') .backgroundColor('#FFFFFF') .borderRadius(16) .padding(16) .shadow({ radius: 4, color: '#10000000', offsetY: 2 })提示:
layoutWeight(1)是 ArkUI 中实现等宽列的核心属性。4 个 Column 都设置了layoutWeight(1),它们会平分 Row 的剩余宽度,实现均匀的网格布局。
二、网格布局机制
2.1 layoutWeight 等分
Row({ space: 8 }) { Column().layoutWeight(1) // 25% 宽度 Column().layoutWeight(1) // 25% 宽度 Column().layoutWeight(1) // 25% 宽度 Column().layoutWeight(1) // 25% 宽度 }宽度计算方式:
父容器宽度 = 360 - 16 - 16 = 328vp(减去卡片左右 padding) 间距总和 = 8vp × 3 = 24vp(3 个间隔) 剩余宽度 = 328 - 24 = 304vp 每列宽度 = 304 / 4 = 76vp2.2 等分 vs 固定宽度
| 布局方式 | 代码 | 优点 | 缺点 |
|---|---|---|---|
| layoutWeight | layoutWeight(1) | 自适应屏幕宽度 | 需要父容器有明确宽度 |
| 固定宽度 | width(70) | 精确控制 | 不同屏幕表现不一致 |
| 百分比 | width('25%') | 按比例分配 | 需手动计算 |
三、占位图设计
3.1 占位图容器
Column() { Text('🐶') .fontSize(24) // Emoji 占位 } .width(64) .height(64) .backgroundColor('#FFF3E0') .borderRadius(12) .justifyContent(FlexAlign.Center)3.2 占位图参数
| 参数 | 值 | 说明 |
|---|---|---|
| 容器尺寸 | 64×64vp | 适中大小 |
| 背景色 | #FFF3E0 | 浅橙,与主色调呼应 |
| 圆角 | 12vp | 圆角矩形 |
| Emoji 大小 | 24fp | 清晰可辨 |
| 内容居中 | FlexAlign.Center | 垂直居中 |
3.3 真实图片替换
// 后续可替换为真实图片 Column() { Image($r('app.media.growth_photo')) .width(64) .height(64) .borderRadius(12) .objectFit(ImageFit.Cover) }四、标签文字设计
4.1 标签样式
Text(label) .fontSize(11) // 小字号 .fontColor('#666666') // 灰色4.2 标签与占位图的间距
Column({ space: 4 }) { // 占位图 // 标签文字(间距 4vp) }五、卡片标题与结构
5.1 标题
Text('成长记录') .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor('#333333') .width('100%')5.2 卡片容器
Column({ space: 12 }) { // 标题 // 网格内容 } .width('100%') .backgroundColor('#FFFFFF') .borderRadius(16) .padding(16) // 统一内边距 16vp .shadow({ radius: 4, color: '#10000000', offsetY: 2 })六、数据驱动渲染
6.1 静态数据
// 使用静态数组渲染 ForEach(['幼年', '6个月', '1岁', '2岁'], (label: string) => { // 网格项 })6.2 动态数据
// 使用动态数据渲染 interface GrowthStage { label: string photo: Resource date: string } @State growthStages: GrowthStage[] = [ { label: '幼年', photo: $r('app.media.puppy'), date: '2022-02-14' }, { label: '6个月', photo: $r('app.media.six_months'), date: '2022-08-14' }, { label: '1岁', photo: $r('app.media.one_year'), date: '2023-02-14' }, { label: '2岁', photo: $r('app.media.two_years'), date: '2024-02-14' } ] ForEach(this.growthStages, (stage: GrowthStage) => { Column({ space: 4 }) { Image(stage.photo) .width(64).height(64).borderRadius(12) Text(stage.label).fontSize(11) } .layoutWeight(1) .alignItems(HorizontalAlign.Center) })七、网格布局的应用场景
7.1 萌宠日记中的网格布局
| 页面 | 网格内容 | 列数 | 布局方式 |
|---|---|---|---|
| 宠物档案 | 成长阶段 | 4 列 | layoutWeight |
| 相册 | 照片墙 | 3 列 | Grid 组件 |
| 快捷操作 | 功能图标 | 5 列 | layoutWeight |
| 活动统计 | 活动类型 | 3 列 | layoutWeight |
7.2 网格布局选择
| 布局需求 | 推荐方案 | 理由 |
|---|---|---|
| 少量固定列(≤ 5) | Row + layoutWeight | 简单、灵活 |
| 大量动态数据 | Grid 组件 | 支持滚动、虚拟化 |
| 不规则网格 | Flex + Wrap | 自动换行 |
八、交互扩展
8.1 点击查看详情
Column({ space: 4 }) { // 占位图 // 标签 } .layoutWeight(1) .alignItems(HorizontalAlign.Center) .onClick(() => { console.log('View growth stage:', label) // 跳转到该阶段的详细记录 if (this.onNavigateToStage) { this.onNavigateToStage(label) } })8.2 添加新阶段
// 添加新的成长阶段 addGrowthStage(stage: GrowthStage): void { this.growthStages.push(stage) // @State 驱动 UI 更新 }九、响应式适配
9.1 不同屏幕适配
| 屏幕宽度 | 每列宽度 | 占位图尺寸 | 标签字号 |
|---|---|---|---|
| < 360vp | 约 66vp | 56×56 | 10fp |
| 360-414vp | 约 76vp | 64×64 | 11fp |
| 414-600vp | 约 86vp | 72×72 | 12fp |
| > 600vp | 约 106vp | 80×80 | 13fp |
9.2 响应式布局实现
getGrowthItemSize(): number { const width = this.getScreenWidth() if (width >= 600) return 80 if (width >= 414) return 72 if (width >= 360) return 64 return 56 }十、最佳实践
10.1 网格布局设计原则
有序列表 — 网格布局的 5 个原则:
- 等宽优先:使用 layoutWeight 实现等宽列,自适应屏幕宽度
- 间距统一:列间距使用 Row 的 space 参数,保持一致性
- 内容居中:网格项内容居中对齐,视觉平衡
- 占位图统一:所有占位图使用相同尺寸和样式
- 标签辅助:图片下方配合文字标签,明确含义
10.2 萌宠日记成长记录卡片总结
| 设计要素 | 值 | 说明 |
|---|---|---|
| 列数 | 4 列 | 幼年、6个月、1岁、2岁 |
| 布局方式 | Row + layoutWeight(1) | 等宽分布 |
| 列间距 | 8vp | Row 的 space 参数 |
| 占位图尺寸 | 64×64vp | 圆角 12vp |
| 标签字号 | 11fp | 灰色 |
| 卡片内边距 | 16vp | 统一 |
| 卡片圆角 | 16vp | 统一风格 |
总结
本文从萌宠日记的成长记录卡片实现出发,深入解析了网格布局的完整方法:
- 卡片结构:标题 + 4 列网格 + 标签
- layoutWeight 等分:4 个 Column 均分 Row 宽度
- 占位图设计:64×64 圆角容器 + Emoji 占位
- 标签文字:11fp 小字号标签
- 数据驱动:ForEach 动态渲染网格项
- 网格布局应用:萌宠日记中多种网格布局场景
- 交互扩展:点击查看详情、添加新阶段
- 响应式适配:不同屏幕尺寸自适应
网格布局是信息展示的重要方式,Row + layoutWeight 的组合适合固定列数的场景,Grid 组件则适合大量动态数据的网格展示。
下一篇我们将深入编辑按钮与交互反馈,解析档案页中编辑按钮的设计与交互。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- Row 组件参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-row
- layoutWeight 属性:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-layout-constraints
- Grid 组件参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-grid
- ForEach 使用:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-foreach
- Image 组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-image
- 卡片设计指南:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/design-cards
- 响应式布局:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/responsive-layout
- 布局基础:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkui-layout