HarmonyOS ArkUI List 侧滑删除与分组粘性标题实战指南

在移动应用开发中,列表(List)是最常用的UI组件之一。HarmonyOS的ArkUI框架提供了功能强大的List组件,支持多种高级交互效果。本文将重点介绍两个提升用户体验的核心功能:侧滑删除(swipeAction)和分组粘性标题(sticky),并通过两个完整案例演示如何在实际项目中应用这些特性。

1. List组件基础与高级特性概述

List组件是HarmonyOS中用于展示结构化数据的滚动容器,具有以下核心特点:

  • 自动滚动 :当内容超出可视区域时自动提供滚动功能
  • 灵活布局 :支持垂直和水平两种滚动方向
  • 高效渲染 :提供条件渲染、循环渲染和懒加载等优化手段
  • 丰富交互 :支持点击、长按、侧滑等多种交互方式

在通讯录、消息列表、商品展示等场景中,List组件的高效实现直接影响用户体验。我们特别关注的两个高级特性:

// 基础List结构示例
List() {
  ForEach(this.items, (item) => {
    ListItem() {
      // 列表项内容
    }
  })
}

1.1 侧滑删除实现原理

侧滑删除是现代移动应用中常见的交互模式,允许用户通过水平滑动列表项来触发删除或其他操作。ArkUI通过 swipeAction 属性实现这一功能:

  • Builder模式 :使用@Builder构建侧滑操作按钮
  • 方向控制 :可配置左侧(end)或右侧(start)滑动
  • 事件绑定 :为操作按钮绑定点击事件处理逻辑

1.2 分组粘性标题工作机制

分组列表中的粘性标题(sticky header)在滚动时会固定在列表顶部,直到下一组标题将其顶替。这种设计:

  • 提升内容组织结构可视性
  • 方便用户快速定位到特定分组
  • 通过 ListItemGroup sticky 属性协同实现

2. 通讯录分组列表实现

下面我们实现一个带粘性标题的分组通讯录列表,包含以下功能:

  • 按字母分组联系人
  • 粘性标题效果
  • 快速返回顶部按钮

2.1 数据结构设计

首先定义联系人和分组的数据结构:

class Contact {
  key: string = util.generateRandomUUID(true);
  name: string;
  avatar: Resource;
  
  constructor(name: string, avatar: Resource) {
    this.name = name;
    this.avatar = avatar;
  }
}

// 分组数据示例
private groups = [
  {
    title: "A",
    contacts: [
      new Contact("Alice", $r("app.media.avatar1")),
      new Contact("Andy", $r("app.media.avatar2"))
    ]
  },
  {
    title: "B",
    contacts: [
      new Contact("Bob", $r("app.media.avatar3")),
      new Contact("Betty", $r("app.media.avatar4"))
    ]
  }
];

2.2 分组标题构建器

使用@Builder创建分组标题组件:

@Builder
groupHeader(title: string) {
  Text(title)
    .fontSize(20)
    .backgroundColor('#F5F5F5')
    .width('100%')
    .padding(10)
}

2.3 完整列表实现

组合List、ListItemGroup和sticky属性:

@Entry
@Component
struct ContactsList {
  private scroller: Scroller = new Scroller();
  
  build() {
    Stack({ alignContent: Alignment.BottomEnd }) {
      List({ space: 10, scroller: this.scroller }) {
        ForEach(this.groups, (group) => {
          ListItemGroup({ header: this.groupHeader(group.title) }) {
            ForEach(group.contacts, (contact) => {
              ListItem() {
                Row() {
                  Image(contact.avatar)
                    .width(40).height(40).margin(10)
                  Text(contact.name).fontSize(18)
                }
                .width('100%')
              }
            })
          }
        })
      }
      .width('100%')
      .sticky(StickyStyle.Header) // 启用粘性标题
      
      // 返回顶部按钮
      Button() {
        Image($r("app.media.arrow_up"))
          .width(30).height(30)
      }
      .onClick(() => {
        this.scroller.scrollToIndex(0)
      })
      .margin({ bottom: 30, right: 20 })
    }
  }
}

提示 :粘性标题效果需要同时满足三个条件:

  1. 使用ListItemGroup分组
  2. 为List设置sticky属性
  3. 为ListItemGroup提供header构建器

3. 消息列表侧滑删除实现

接下来我们实现一个消息列表,支持左滑显示删除按钮。

3.1 消息数据结构

class Message {
  key: string = util.generateRandomUUID(true);
  sender: string;
  content: string;
  time: string;
  unread: boolean;
  
  constructor(sender: string, content: string, time: string) {
    this.sender = sender;
    this.content = content;
    this.time = time;
    this.unread = Math.random() > 0.5;
  }
}

@State messages: Message[] = [
  new Message("张三", "晚上一起吃饭吗?", "10:30"),
  new Message("李四", "项目文档已更新", "09:15"),
  // 更多消息...
];

3.2 侧滑操作构建器

创建删除按钮的Builder:

@Builder
deleteButton(index: number) {
  Button() {
    Image($r("app.media.delete"))
      .width(25).height(25)
  }
  .width(80)
  .height('100%')
  .backgroundColor(Color.Red)
  .onClick(() => {
    this.messages.splice(index, 1);
  })
}

3.3 完整消息列表实现

@Entry
@Component
struct MessageList {
  build() {
    List({ space: 5 }) {
      ForEach(this.messages, (message, index) => {
        ListItem() {
          Row() {
            // 未读标记
            if (message.unread) {
              Circle({ width: 8, height: 8 })
                .fill(Color.Blue)
                .margin({ right: 10 })
            }
            
            Column() {
              Row() {
                Text(message.sender)
                  .fontSize(18)
                  .fontWeight(FontWeight.Bold)
                Text(message.time)
                  .fontSize(14)
                  .fontColor('#999')
                  .margin({ left: 10 })
              }
              .width('100%')
              .justifyContent(FlexAlign.SpaceBetween)
              
              Text(message.content)
                .fontSize(16)
                .margin({ top: 5 })
            }
            .layoutWeight(1)
          }
          .padding(10)
          .width('100%')
        }
        .swipeAction({ end: this.deleteButton(index) }) // 右侧滑出删除按钮
      })
    }
    .width('100%')
    .height('100%')
    .divider({ 
      strokeWidth: 1, 
      color: '#EEE',
      startMargin: 60,
      endMargin: 0
    })
  }
}

4. 性能优化与最佳实践

在实现复杂列表时,需要注意以下性能优化点:

4.1 列表渲染优化

优化策略 实现方式 适用场景
键值生成 为ForEach提供稳定唯一的key 所有动态列表
懒加载 使用LazyForEach替代ForEach 超长列表
预渲染 设置cachedCount 快速滚动场景
轻量组件 简化ListItem内部结构 复杂列表项

4.2 交互体验提升技巧

  • 视觉反馈 :为侧滑操作添加适当的动画效果
  • 撤销机制 :删除操作后提供撤销选项
  • 分组索引 :添加字母索引条方便快速导航
  • 加载更多 :滚动到底部时自动加载更多数据
// 懒加载示例
List() {
  LazyForEach(this.dataSource, (item) => {
    ListItem() {
      // 列表项内容
    }
  })
}
.cachedCount(5) // 预渲染5个项目

通过合理运用ArkUI List组件的高级特性,可以显著提升应用的交互体验和视觉表现。本文的两个案例展示了如何在实际项目中实现这些功能,开发者可以根据具体需求进行调整和扩展。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐