暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

17 HarmonyOS NEXT UVList组件开发指南(四)

原创 若城 2025-03-09
191

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦!

HarmonyOS NEXT UVList组件开发指南(四)

第四篇:UVList组件高级特性与性能优化

1. 高级特性

1.1 自定义渲染

除了使用默认的渲染方式外,UVList组件还支持自定义渲染,以满足更复杂的UI需求:

@Entry @Component struct CustomRenderDemo { @State listItems: Array<ListItemProps> = [ { title: '自定义项1', note: '自定义渲染示例' }, { title: '自定义项2', note: '自定义渲染示例' } ]; // 自定义渲染函数 @Builder private renderCustomItem(item: ListItemProps) { Row() { Circle({ width: 8, height: 8 }) .fill('#2979ff') .margin({ right: 8 }) Column() { Text(item.title) .fontSize(16) .fontWeight(FontWeight.Medium) if (item.note) { Text(item.note) .fontSize(14) .fontColor('#999') .margin({ top: 4 }) } } .alignItems(HorizontalAlign.Start) } .width('100%') .padding(16) .backgroundColor(Color.White) .borderRadius(8) } build() { Column() { // 使用自定义渲染的列表 List() { ForEach(this.listItems, (item: ListItemProps) => { ListItem() { this.renderCustomItem(item) } .padding({ left: 16, right: 16, top: 4, bottom: 4 }) }) } .width('100%') .divider({ strokeWidth: 1, color: '#f5f5f5', startMargin: 16, endMargin: 16 }) .borderRadius(8) .backgroundColor(Color.White) } .width('100%') .height('100%') .backgroundColor('#f5f5f5') .padding(16) } }

1.2 分组列表

通过扩展UVList组件,可以实现分组列表功能:

// 分组列表数据接口 interface GroupListProps { // 分组标题 title?: string; // 分组数据 groups: Array<{ // 分组标题 title: string; // 分组项 items: Array<ListItemProps>; }>; } @Component struct GroupList { private props: GroupListProps = {} as GroupListProps; build() { Column() { // 列表标题(如果有) if (this.props.title) { Text(this.props.title) .fontSize(18) .fontWeight(FontWeight.Bold) .width('100%') .textAlign(TextAlign.Start) .padding({ left: 16, right: 16, top: 16, bottom: 8 }) } // 遍历分组 ForEach(this.props.groups, (group, groupIndex) => { Column() { // 分组标题 Text(group.title) .fontSize(16) .fontWeight(FontWeight.Medium) .width('100%') .textAlign(TextAlign.Start) .padding({ left: 16, right: 16, top: 16, bottom: 8 }) // 分组内容 UVList({ props: { items: group.items } }) } .margin({ top: groupIndex > 0 ? 16 : 0 }) }) } .width('100%') } }

1.3 可展开列表

通过扩展UVList组件,可以实现可展开列表功能:

// 可展开列表项接口 interface ExpandableListItemProps extends ListItemProps { // 子项 children?: Array<ListItemProps>; // 是否展开 expanded?: boolean; } @Component struct ExpandableListItem { @ObjectLink item: ExpandableListItemProps; build() { Column() { // 主项 Row() { // 标题 Text(this.item.title) .fontSize(16) .fontWeight(FontWeight.Medium) .layoutWeight(1) // 展开/收起图标 Image(this.item.expanded ? $r('app.media.ic_arrow_up') : $r('app.media.ic_arrow_down')) .width(16) .height(16) .objectFit(ImageFit.Contain) } .width('100%') .padding(16) .backgroundColor(Color.White) .borderRadius(8) .onClick(() => { // 切换展开状态 this.item.expanded = !this.item.expanded; }) // 子项(如果展开) if (this.item.expanded && this.item.children) { Column() { ForEach(this.item.children, (child: ListItemProps) => { UVListItem({ item: child, showIcon: true, showRightText: true, navigable: true }) }) } .padding({ left: 16 }) } } .width('100%') } }

2. 性能优化

2.1 状态管理优化

// 优化前:整个列表数据作为响应式状态 @State listItems: Array<ListItemProps> = []; // 优化后:将不变的数据与变化的状态分离 private listItemsData: Array<{ id: string; title: string; note: string; icon?: string | Resource; }> = []; @State private listItemsState: Record<string, { disabled: boolean; expanded: boolean; }> = {}; // 构建列表项 private getListItems(): Array<ListItemProps> { return this.listItemsData.map(item => ({ ...item, disabled: this.listItemsState[item.id]?.disabled || false, onClick: () => this.handleItemClick(item.id) })); }

优化说明:

  1. 将不变的数据(如标题、描述、图标)与变化的状态(如禁用状态、展开状态)分离
  2. 减少响应式数据的体积,提高性能
  3. 按需构建列表项,避免不必要的更新

2.2 渲染性能优化

// 优化前:直接在ForEach中渲染所有列表项 ForEach(this.listItems, (item: ListItemProps) => { ListItem() { UVListItem({ item: item, // 其他属性 }) } }) // 优化后:使用LazyForEach按需渲染列表项 LazyForEach(new DataSource(this.listItems), (item: ListItemProps) => { ListItem() { UVListItem({ item: item, // 其他属性 }) } }, item => item.id)

优化说明:

  1. 使用LazyForEach代替ForEach,实现按需渲染
  2. 只渲染可见区域的列表项,减少内存占用和提高渲染性能
  3. 为每个列表项提供唯一的key,优化更新性能

2.3 条件渲染优化

// 优化前:频繁的条件判断 build() { Row() { if (this.showIcon && this.item.icon) { // 渲染图标 } Column() { Text(this.item.title) if (this.item.note) { Text(this.item.note) } } Row() { if (this.showRightText && this.item.rightText) { Text(this.item.rightText) } if (this.navigable && this.item.showArrow !== false) { Image($r('app.media.ic_arrow_right')) } } } } // 优化后:提前计算条件结果 build() { // 提前计算条件结果 const showIcon = this.showIcon && this.item.icon; const showNote = this.item.note != null; const showRightText = this.showRightText && this.item.rightText; const showArrow = this.navigable && this.item.showArrow !== false; Row() { if (showIcon) { // 渲染图标 } Column() { Text(this.item.title) if (showNote) { Text(this.item.note) } } Row() { if (showRightText) { Text(this.item.rightText) } if (showArrow) { Image($r('app.media.ic_arrow_right')) } } } }

优化说明:

  1. 提前计算条件结果,减少重复计算
  2. 简化条件判断,提高代码可读性
  3. 减少条件判断的复杂度,提高渲染性能

3. 内存优化

3.1 资源复用

// 优化前:每次渲染都创建新的样式对象 build() { Row() { // 内容 } .width('100%') .padding({ left: 16, right: 16, top: 12, bottom: 12 }) .backgroundColor(this.item.disabled ? '#fafafa' : Color.White) .borderRadius(8) } // 优化后:复用样式对象 // 定义常量样式 private static readonly COMMON_STYLE = { width: '100%', borderRadius: 8, padding: { left: 16, right: 16, top: 12, bottom: 12 } }; private static readonly NORMAL_BG = Color.White; private static readonly DISABLED_BG = '#fafafa'; build() { Row() { // 内容 } .width(UVListItem.COMMON_STYLE.width) .padding(UVListItem.COMMON_STYLE.padding) .backgroundColor(this.item.disabled ? UVListItem.DISABLED_BG : UVListItem.NORMAL_BG) .borderRadius(UVListItem.COMMON_STYLE.borderRadius) }

优化说明:

  1. 使用静态常量定义样式,避免重复创建样式对象
  2. 复用样式对象,减少内存占用
  3. 提高样式一致性,便于维护

3.2 图片资源优化

// 优化前:直接使用图片资源 Image(this.item.icon) .width(24) .height(24) .objectFit(ImageFit.Contain) // 优化后:根据需要加载不同尺寸的图片 private getOptimizedIcon(icon: string | Resource): string | Resource { if (typeof icon === 'string') { return icon; } // 根据当前设备分辨率选择合适的图片资源 const devicePixelRatio = getDevicePixelRatio(); if (devicePixelRatio <= 1) { return $r('app.media.icon_small'); } else if (devicePixelRatio <= 2) { return $r('app.media.icon_medium'); } else { return $r('app.media.icon_large'); } } // 使用优化后的图片资源 Image(this.getOptimizedIcon(this.item.icon)) .width(24) .height(24) .objectFit(ImageFit.Contain)

优化说明:

  1. 根据设备分辨率加载不同尺寸的图片资源
  2. 减少内存占用,提高渲染性能
  3. 优化图片显示效果

4. 交互优化

4.1 点击反馈优化

// 优化前:简单的点击处理 .onClick(() => { if (!this.item.disabled) { // 执行点击操作 this.item.onClick?.(); } }) // 优化后:添加点击反馈效果 .onClick(() => { if (!this.item.disabled) { // 执行点击操作 this.item.onClick?.(); } }) .stateStyles({ pressed: { opacity: 0.7, backgroundColor: '#f0f0f0' }, disabled: { opacity: 0.5, backgroundColor: '#fafafa' } })

优化说明:

  1. 添加状态样式,提供按下和禁用状态的视觉反馈
  2. 使用opacity和backgroundColor变化提供明显的交互反馈
  3. 提高用户体验,增强交互感知

4.2 手势交互优化

// 优化前:仅支持点击操作 .onClick(() => { // 点击处理 }) // 优化后:支持多种手势交互 .gesture( GestureGroup(GestureMode.Exclusive, TapGesture() .onAction(() => { // 点击处理 if (!this.item.disabled) { this.item.onClick?.(); } }), LongPressGesture() .onAction(() => { // 长按处理 if (!this.item.disabled && this.item.onLongPress) { this.item.onLongPress(); } }), SwipeGesture() .onAction((event: SwipeGestureEvent) => { // 滑动处理 if (!this.item.disabled && this.item.onSwipe) { this.item.onSwipe(event); } }) ) )

优化说明:

  1. 支持点击、长按、滑动等多种手势交互
  2. 使用GestureGroup组合多种手势,并设置为互斥模式
  3. 为不同手势提供不同的处理函数,增强交互丰富性

4.3 动画效果优化

// 优化前:无动画效果 @Component struct UVListItem { // 组件属性 build() { // 构建UI } } // 优化后:添加动画效果 @Component struct UVListItem { // 组件属性 @State private isPressed: boolean = false; @State private isAnimating: boolean = false; build() { Row() { // 列表项内容 } .width('100%') .padding(16) .backgroundColor(this.isPressed ? '#f0f0f0' : Color.White) .borderRadius(8) .opacity(this.item.disabled ? 0.5 : 1) .animation({ duration: 200, curve: Curve.EaseInOut, iterations: 1, playMode: PlayMode.Normal }) .onTouch((event: TouchEvent) => { if (event.type === TouchType.Down) { this.isPressed = true; } else if (event.type === TouchType.Up || event.type === TouchType.Cancel) { this.isPressed = false; } }) .onClick(() => { if (!this.item.disabled) { // 点击动画 this.isAnimating = true; animateTo({ duration: 100, onFinish: () => { this.isAnimating = false; // 执行点击操作 this.item.onClick?.(); } }, () => { this.isPressed = true; }) animateTo({ duration: 100, delay: 100 }, () => { this.isPressed = false; }) } }) } }

优化说明:

  1. 添加按下状态和动画状态管理
  2. 使用animation属性为样式变化添加过渡效果
  3. 使用animateTo实现点击时的动画序列
  4. 通过onTouch事件精确控制按下状态

5. 总结与最佳实践

在本篇文章中,我们详细介绍了UVList组件的高级特性与性能优化技巧。通过这些优化,可以显著提升UVList组件的性能和用户体验。
通过本系列文章的学习,相信你已经掌握了UVList组件的开发和优化技巧。在实际项目中,可以根据具体需求灵活运用这些技巧,打造出高性能、高体验的列表组件。
下一章节我们将主要讲解实际的应用场景,敬请期待!

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论