
阅读时长:约 20 分钟 | 难度:★★★★☆ | 篇章:第 4 篇 · 二十八星宿模块
对应源码:
entry/src/main/ets/pages/mansion/MansionListPage.ets

前言
玄象项目星宿列表页是二十八星宿模块的主入口。页面采用"四象圆盘 + 星宿列表 + 四象 Tab"的三段式布局,通过 List / ListItem 容器展示星宿基础信息,通过 List 的 layoutWeight 弹性填充实现滚动。本篇将深入剖析玄象项目星宿列表页的实现:从 List / ListItem 容器关系、ForEach 数据驱动渲染、LazyForEach 懒加载优化、@State currentSiXiang 四象切换,到 Canvas 四象圆盘绘制。掌握这套列表页实现方法论,您就能为任何 HarmonyOS 应用打造高效的数据列表页。
提示:玄象项目星宿列表项包含名称、神兽、五行、分野四个字段,通过
Row横向布局实现紧凑展示。
一、MansionListPage 完整布局
1.1 页面结构
typescript
build() {
Column() {
// 顶部标题栏
Row() { ... }
// 四象圆盘
Stack() {
Canvas(this.mansionWheelContext) // 四象分区圆盘
.width(300).height(300)
Column() { ... } // 中心信息
}
// 星宿列表
List({ space: 12 }) {
ForEach(this.mansions, (mansion: MansionInfo) => {
ListItem() { ... } // 星宿行
}, (mansion) => mansion.name)
}
.layoutWeight(1)
.padding({ left: 16, right: 16 })
// 底部四象 Tab
Row() { ... }
}
}
1.2 三段式布局
text
Column (全屏)
├── 顶部标题栏(固定高度)
├── 四象圆盘(320vp 固定高度)
├── List(layoutWeight 弹性填充)
└── 底部四象 Tab(固定高度)
二、List 容器详解
2.1 List 基本用法
typescript
List({ space: 12 }) {
ForEach(this.mansions, (mansion: MansionInfo) => {
ListItem() {
// 列表项内容
}
}, (mansion: MansionInfo) => mansion.name)
}
.layoutWeight(1)
.padding({ left: 16, right: 16 })
.scrollBar(BarState.Off)
2.2 List 关键属性
| 属性 | 值 | 含义 |
|---|---|---|
space |
12 | 列表项间距 12vp |
layoutWeight |
1 | 弹性填充剩余空间 |
padding |
{ left: 16, right: 16 } |
左右边距 |
scrollBar |
BarState.Off |
隐藏滚动条 |
2.3 ListItem 行结构
typescript
ListItem() {
Row() {
Text(mansion.name) // 星宿名称(金色,80px 宽)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(Colors.PRIMARY_GOLD)
.width(80)
Text(mansion.animal) // 神兽
.fontSize(14)
.fontColor(Colors.TEXT_SECONDARY)
.width(60)
Text(mansion.wuXing) // 五行
.fontSize(14)
.fontColor(Colors.TEXT_SECONDARY)
.width(40)
Blank()
Text(mansion.fenYe) // 分野
.fontSize(14)
.fontColor(Colors.TEXT_SECONDARY)
Text('>') // 箭头
.fontSize(18)
.fontColor(Colors.TEXT_DIM)
.margin({ left: 8 })
}
.width('100%')
.padding(16)
.backgroundColor(Colors.BG_CARD)
.borderRadius(12)
.border({ width: 0.5, color: Colors.BG_CARD_BORDER })
.onClick(() => {
router.pushUrl({
url: 'pages/mansion/MansionDetailPage',
params: { mansionName: mansion.name }
});
})
}
三、列表项布局
3.1 行布局结构
text
┌──────────────────────────────────────┐
│ 角宿 蛟 木 郑国 > │
│ ↑name ↑animal ↑wuXing ↑fenYe ↑arrow│
└──────────────────────────────────────┘
3.2 字段宽度
| 字段 | 宽度 | 颜色 |
|---|---|---|
name |
80vp | 金色 |
animal |
60vp | 灰色 |
wuXing |
40vp | 灰色 |
fenYe |
自适应 | 灰色 |
> |
固定 | 深灰 |
3.3 行样式
typescript
.padding(16)
.backgroundColor(Colors.BG_CARD)
.borderRadius(12)
.border({ width: 0.5, color: Colors.BG_CARD_BORDER })
四、数据驱动渲染
4.1 ForEach 渲染
typescript
ForEach(this.mansions, (mansion: MansionInfo) => {
ListItem() { ... }
}, (mansion: MansionInfo) => mansion.name)
4.2 数据变化
当 currentSiXiang 切换时,数据源变化:
typescript
.onClick(() => {
this.currentSiXiang = siXiang;
this.mansions = MansionData.getMansionsBySiXiang(siXiang);
// @State 变化,List 自动重新渲染
})
五、LazyForEach 懒加载优化
5.1 LazyForEach 与 ForEach 对比
| 维度 | ForEach | LazyForEach |
|---|---|---|
| 渲染方式 | 全量渲染 | 按需渲染 |
| 性能 | 数据量大时卡顿 | 数据量大时流畅 |
| 适用 | ≤ 100 项 | ≥ 100 项 |
| 数据源 | 普通数组 | DataSource 对象 |
5.2 LazyForEach 用法
typescript
class MansionDataSource extends BasicDataSource<MansionInfo> {
private data: MansionInfo[] = [];
totalCount(): number {
return this.data.length;
}
getData(index: number): MansionInfo {
return this.data[index];
}
}
// 在页面中使用
LazyForEach(this.dataSource, (item: MansionInfo) => {
ListItem() { ... }
}, (item: MansionInfo) => item.name)
玄象项目星宿列表仅 7 项,ForEach 足够。但若未来扩展到全部 28 宿,可考虑 LazyForEach。
六、四象圆盘 Canvas
6.1 圆盘结构
typescript
private drawMansionWheel = (canvas: CanvasRenderingContext2D, w: number, h: number) => {
const cx = w / 2, cy = h / 2;
const outerR = Math.min(w, h) / 2 - 10;
// 外圈
canvas.strokeStyle = Colors.PRIMARY_GOLD;
canvas.lineWidth = 2;
canvas.beginPath();
canvas.arc(cx, cy, outerR, 0, Math.PI * 2);
canvas.stroke();
// 四象分区
const siXiangColors = ['#00BCD4', '#E91E63', '#ECEFF1', '#9C27B0'];
// ...
}
6.2 四象分区算法
typescript
for (let i = 0; i < 4; i++) {
const startAngle = (i * 90 - 90) * Math.PI / 180;
const endAngle = ((i + 1) * 90 - 90) * Math.PI / 180;
canvas.fillStyle = siXiangColors[i] + '22';
canvas.beginPath();
canvas.moveTo(cx, cy);
canvas.arc(cx, cy, outerR, startAngle, endAngle);
canvas.closePath();
canvas.fill();
}
七、底部四象 Tab
7.1 Tab 实现
typescript
Row() {
ForEach(MansionData.SI_XIANG_ORDER, (siXiang: string) => {
Column({ space: 4 }) {
Text(this.getSiXiangIcon(siXiang))
.fontSize(24)
Text(this.getSiXiangName(siXiang))
.fontSize(12)
.fontColor(siXiang === this.currentSiXiang ? Colors.PRIMARY_GOLD : Colors.TEXT_DIM)
}
.layoutWeight(1)
.padding({ top: 8, bottom: 8 })
.backgroundColor(siXiang === this.currentSiXiang ? '#1A2030' : 'transparent')
.onClick(() => {
this.currentSiXiang = siXiang;
this.mansions = MansionData.getMansionsBySiXiang(siXiang);
})
}, (siXiang: string) => siXiang)
}
7.2 四象图标
typescript
private getSiXiangIcon(siXiang: string): string {
switch (siXiang) {
case '苍龙': return '🐉';
case '朱雀': return '🔥';
case '白虎': return '🐯';
case '玄武': return '🐢';
default: return '';
}
}
八、列表页性能优化
8.1 避免重复渲染
玄象项目使用 keyGenerator 避免不必要的重复渲染。
8.2 固定高度
给 ListItem 固定高度,帮助 List 计算滚动范围。
8.3 懒加载
数据量增大时,切换为 LazyForEach。
九、列表页的交互反馈
9.1 点击跳转
typescript
.onClick(() => {
router.pushUrl({
url: 'pages/mansion/MansionDetailPage',
params: { mansionName: mansion.name }
});
})
9.2 四象切换
切换时,mansions 数组更新,List 自动刷新。
十、玄象项目列表页设计总结
10.1 综述
玄象项目星宿列表页采用"四象圆盘 + 列表 + Tab"三段式布局,数据驱动渲染。
10.2 关键数据流
text
MansionData.ets
↓ filter
mansions数组
↓ ForEach
ListItem
↓ onClick
router.pushUrl
九、列表页常见问题
9.1 List 与 Scroll 的区别
| 特性 | List | Scroll |
|---|---|---|
| 子元素类型 | 仅 ListItem | 任意组件 |
| 懒加载 | 支持 LazyForEach | 不支持 |
| 性能 | 优(虚拟滚动) | 一般(全量渲染) |
| 适用场景 | 长列表 | 短内容滚动 |
9.2 四象切换的性能优化
玄象项目四象切换时触发 List 数据更新。星宿列表仅 7 项,ForEach 足够。若未来扩展到全部 28 宿,应改用 LazyForEach:
typescript
LazyForEach(this.mansionsDataSource, (item: MansionInfo) => {
ListItem() { ... }
}, (item: MansionInfo) => item.name)
9.3 列表项点击事件的防抖
typescript
private lastClickTime: number = 0;
ListItem() { ... }
.onClick(() => {
const now = Date.now();
if (now - this.lastClickTime < 500) return;
this.lastClickTime = now;
router.pushUrl({ url: 'pages/mansion/MansionDetailPage', params: { mansionName: mansion.name } });
})
十、四象圆盘的视觉设计
10.1 四象颜色的文化含义
| 四象 | 颜色 | 五行 | 方位 | 季节 |
|---|---|---|---|---|
| 苍龙 | #00BCD4 | 木 | 东 | 春 |
| 朱雀 | #E91E63 | 火 | 南 | 夏 |
| 白虎 | #ECEFF1 | 金 | 西 | 秋 |
| 玄武 | #9C27B0 | 水 | 北 | 冬 |
10.2 圆盘交互的未来扩展
玄象项目四象圆盘未来可扩展为:
- 触摸选中四象:点击圆盘分区自动切换对应四象列表
- 旋转动画:圆盘自动缓慢旋转
- 星宿高亮:当前选中的星宿在圆盘上高亮显示
总结
本篇以玄象项目星宿列表页为蓝本,深入剖析了 ArkUI 列表页实现:从 List / ListItem 容器、ForEach 数据驱动渲染、LazyForEach 懒加载优化,到 @State currentSiXiang 四象切换、Canvas 四象圆盘绘制。掌握这套列表页实现方法论,您就能为任何 HarmonyOS 应用打造高效的数据列表页。
下一篇:《33 · MansionDetailPage 详情页:星宿图说 + 五行属性 + 占验断语》,将带您深入玄象项目星宿详情页的实现。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- HarmonyOS 官方文档:List 组件
- HarmonyOS 官方文档:LazyForEach
- 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net