HarmonyOS:使用List实现分组列表(包含粘性标题)

一、支持分组列表

在列表中支持数据的分组展示,可以使列表显示结构清晰,查找方便,从而提高使用效率。分组列表在实际应用中十分常见,如下图所示联系人列表。
联系人分组列表


在List组件中使用ListItemGroup 对项目进行分组,可以构建二维列表。

在List组件中可以直接使用一个或者多个ListItemGroup组件,ListItemGroup的宽度默认充满List组件。在初始化ListItemGroup时,可通过header参数设置列表分组的头部组件。

复制代码
@Entry
@Component
struct ContactsList {
  
  @Builder itemHead(text: string) {
    // 列表分组的头部组件,对应联系人分组A、B等位置的组件
    Text(text)
      .fontSize(20)
      .backgroundColor('#fff1f3f5')
      .width('100%')
      .padding(5)
  }

  build() {
    List() {
      ListItemGroup({ header: this.itemHead('A') }) {
        // 循环渲染分组A的ListItem
      }

      ListItemGroup({ header: this.itemHead('B') }) {
        // 循环渲染分组B的ListItem
      }
    }
  }
}

如果多个ListItemGroup 结构类似,可以将多个分组的数据组成数组,然后使用ForEach 对多个分组进行循环渲染。例如在联系人列表中,将每个分组的联系人数据contacts和对应分组的标题title数据进行组合,定义为数组contactsGroups。然后在ForEach中对contactsGroups进行循环渲染,即可实现多个分组的联系人列表。可参考添加粘性标题示例代码。

二、添加粘性标题

粘性标题是一种常见的标题模式,常用于定位字母列表的头部元素。如下图所示,在联系人列表中滚动A部分时,B部分开始的头部元素始终处于A的下方。而在开始滚动B部分时,B的头部会固定在屏幕顶部,直到所有B的项均完成滚动后,才被后面的头部替代。
粘性标题不仅有助于阐明列表中数据的表示形式和用途,还可以帮助用户在大量信息中进行数据定位,从而避免用户在标题所在的表的顶部与感兴趣区域之间反复滚动。
粘性标题--联系人分组列表


List组件的sticky属性配合ListItemGroup组件使用,用于设置ListItemGroup中的头部组件是否呈现吸顶效果或者尾部组件是否呈现吸底效果。
通过给List组件设置sticky属性为StickyStyle.Header,即可实现列表的粘性标题效果。如果需要支持吸底效果,可以通过footer参数初始化ListItemGroup的底部组件,并将sticky属性设置为StickyStyle.Footer。

三、完整示例代码

TestContactsList.ets

复制代码
import { util } from '@kit.ArkTS'

class Contact {
  contactkey: string = util.generateRandomUUID(true);
  name: string;
  avatar: Resource;

  constructor(name: string, avatar: Resource) {
    this.name = name;
    this.avatar = avatar;
  }
}

class ContactsGroup {
  title: string = '';
  key: string = '';
  contacts: Array<object> | null = null;
}

let contactsGroups: object[] = [
  {
    title: 'A',
    key: util.generateRandomUUID(true),
    contacts: [
      new Contact('Andy', $r('app.media.circle')),
      new Contact('安沃', $r('app.media.circle')),
      new Contact('昂科1', $r('app.media.circle')),
      new Contact('昂科2', $r('app.media.circle')),
      new Contact('昂科3', $r('app.media.circle')),
    ]
  } as ContactsGroup,
  {
    title: 'B',
    key: util.generateRandomUUID(true),
    contacts: [
      new Contact('Ben', $r('app.media.circle')),
      new Contact('蹦高', $r('app.media.circle')),
      new Contact('巴掌1', $r('app.media.circle')),
      new Contact('巴掌2', $r('app.media.circle')),
    ]
  } as ContactsGroup,
  {
    title: 'C',
    key: util.generateRandomUUID(true),
    contacts: [
      new Contact('ChenL', $r('app.media.circle')),
      new Contact('成才', $r('app.media.circle')),
      new Contact('程程1', $r('app.media.circle')),
      new Contact('程程2', $r('app.media.circle')),
      new Contact('程程3', $r('app.media.circle')),
      new Contact('程程4', $r('app.media.circle')),
    ]
  } as ContactsGroup,
  {
    title: 'D',
    key: util.generateRandomUUID(true),
    contacts: [
      new Contact('DIba', $r('app.media.circle')),
      new Contact('迪迪1', $r('app.media.circle')),
      new Contact('迪迪2', $r('app.media.circle')),
      new Contact('迪迪3', $r('app.media.circle')),
    ]
  } as ContactsGroup
]

@Component
struct ItemContact {
  @Prop item: Contact

  build() {
    Row({ space: 10 }) {
      Image(this.item.avatar)
        .width('50vp')
        .height('50vp')
      Text(this.item.name)
        .fontSize(20)
        .fontColor(Color.Black)
        .ellipsisMode(EllipsisMode.END)
        .maxLines(1)
    }
    .width('100%')
    .margin({ top: 16, bottom: 10 })
    .padding({ left: 16 })
    .alignItems(VerticalAlign.Center)
    .justifyContent(FlexAlign.Start)
  }
}

@Entry
@Component
struct TestContactsList {
  @State message: string = '分组列表';

  // 定义分组联系人数据集合contactsGroups数组
  @Builder
  itemHead(text: string) {
    // 列表分组的头部组件,对应联系人分组A、B等位置的组件
    Text(text)
      .fontSize(20)
      .backgroundColor('#fff1f3f5')
      .width('100%')
      .padding(5)
  }

  build() {
    Column({ space: 10 }) {
      Text(this.message)
        .id('TestContactsListHelloWorld')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      List() {
        ForEach(contactsGroups, (itemGroup: ContactsGroup) => {
          ListItemGroup({ header: this.itemHead(itemGroup.title) }) {
            if (itemGroup.contacts) {
              ForEach(itemGroup.contacts, (contact: Contact) => {
                ListItem() {
                  ItemContact({ item: contact })
                }
              }, (item: Contact) => JSON.stringify(item))
            }
          }
        }, (itemGroup: ContactsGroup) => JSON.stringify(itemGroup))
      }
      .sticky(StickyStyle.Header)
      .scrollBar(BarState.Auto)
    }
  }
}
相关推荐
写雨.016 小时前
鸿蒙定位开发服务
华为·harmonyos·鸿蒙
goto_w21 小时前
uniapp上使用webview与浏览器交互,支持三端(android、iOS、harmonyos next)
android·vue.js·ios·uni-app·harmonyos
别说我什么都不会1 天前
ohos.net.http请求HttpResponse header中set-ccokie值被转成array类型
网络协议·harmonyos
码是生活2 天前
鸿蒙开发排坑:解决 resourceManager.getRawFileContent() 获取文件内容为空问题
前端·harmonyos
鸿蒙场景化示例代码技术工程师2 天前
基于Canvas实现选座功能鸿蒙示例代码
华为·harmonyos
小脑斧爱吃鱼鱼2 天前
鸿蒙项目笔记(1)
笔记·学习·harmonyos
鸿蒙布道师2 天前
鸿蒙NEXT开发对象工具类(TS)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
zhang1062092 天前
HarmonyOS 基础组件和基础布局的介绍
harmonyos·基础组件·基础布局
马剑威(威哥爱编程)2 天前
在HarmonyOS NEXT 开发中,如何指定一个号码,拉起系统拨号页面
华为·harmonyos·arkts
GeniuswongAir2 天前
Flutter极速接入IM聊天功能并支持鸿蒙
flutter·华为·harmonyos