HarmonyOS应用《玄象》开发实战:MansionListPage 列表页:List / ListItem / LazyForEach 性能优化

阅读时长:约 20 分钟 | 难度:★★★★☆ | 篇章:第 4 篇 · 二十八星宿模块

对应源码:entry/src/main/ets/pages/mansion/MansionListPage.ets

前言

玄象项目星宿列表页是二十八星宿模块的主入口。页面采用"四象圆盘 + 星宿列表 + 四象 Tab"的三段式布局,通过 List / ListItem 容器展示星宿基础信息,通过 ListlayoutWeight 弹性填充实现滚动。本篇将深入剖析玄象项目星宿列表页的实现:从 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 圆盘交互的未来扩展

玄象项目四象圆盘未来可扩展为:

  1. 触摸选中四象:点击圆盘分区自动切换对应四象列表
  2. 旋转动画:圆盘自动缓慢旋转
  3. 星宿高亮:当前选中的星宿在圆盘上高亮显示

总结

本篇以玄象项目星宿列表页为蓝本,深入剖析了 ArkUI 列表页实现:从 List / ListItem 容器、ForEach 数据驱动渲染、LazyForEach 懒加载优化,到 @State currentSiXiang 四象切换、Canvas 四象圆盘绘制。掌握这套列表页实现方法论,您就能为任何 HarmonyOS 应用打造高效的数据列表页。

下一篇:《33 · MansionDetailPage 详情页:星宿图说 + 五行属性 + 占验断语》,将带您深入玄象项目星宿详情页的实现。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

相关推荐
程序员黑豆2 小时前
鸿蒙应用开发:Refresh + List 下拉刷新组件使用教程
前端·华为·harmonyos
youtootech3 小时前
HarmonyOS 实战教程(九):响应式布局与断点系统 —— 以「柚兔自测量表」为例
华为·harmonyos
山璞3 小时前
将一个 Flutter 项目转为用 ArkUI-X 框架实现(4)
flutter·harmonyos
2501_919749034 小时前
华为鸿蒙隐私文件加密APP—小羊加密室
华为·harmonyos
程序员黑豆4 小时前
鸿蒙开发实战:使用 List 组件构建新闻列表
前端·华为·harmonyos
爱写代码的阿森4 小时前
鸿蒙三方库 | harmony-utils之RegexUtil正则匹配验证详解
服务器·华为·harmonyos·鸿蒙·huawei
qizayaoshuap5 小时前
# 卡片轮播组件开发实战:HarmonyOS ArkTS 优雅轮播效果实现解析
华为·harmonyos
echohelloworld115 小时前
HarmonyOS应用《玄象》开发实战:项目目录约定:common/components/constants/utils/pages 六层架构
harmonyos·鸿蒙
程序员黑豆5 小时前
鸿蒙应用开发:Scroll 组件从入门到实战
前端·华为·harmonyos