HarmonyOS 鸿蒙Next中List组件如何实现“吸顶”效果?

HarmonyOS 鸿蒙Next中List组件如何实现“吸顶”效果? 商品分类列表中,每个分类标题滚动到顶部时应固定。ArkUI 有 sticky 属性吗?

7 回复

更多关于HarmonyOS 鸿蒙Next中List组件如何实现“吸顶”效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


List组件的sticky属性配合ListItemGroup组件使用,用于设置ListItemGroup中的头部组件是否呈现吸顶效果或者尾部组件是否呈现吸底效果。

sticky属性可以设置为 StickyStyle.Header | StickyStyle.Footer 以同时支持header吸顶和footer吸底。从API version 20开始,sticky属性也可以设置为StickyStyle.BOTH,以同时支持header吸顶和footer吸底。

官方示例:

import { util } from '@kit.ArkTS';

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

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

export class ContactsGroupDataSource implements IDataSource {
  private list: object[] = [];
  constructor(list: object[]) {
    this.list = list;
  }
  totalCount(): number {
    return this.list.length;
  }
  getData(index: number): object {
    return this.list[index];
  }
  registerDataChangeListener(listener: DataChangeListener): void {
  }
  unregisterDataChangeListener(listener: DataChangeListener): void {
  }
}

export let contactsGroups: object[] = [
  {
    title: 'A',
    contacts: [
      // app.string.contacts_A_one 资源文件中的value值为'艾佳',app.media.iconA为自定义资源
      new Contact($r('app.string.contacts_A_one'), $r('app.media.iconA')),
      // app.string.contacts_A_two 资源文件中的value值为'安安',app.media.iconB为自定义资源
      new Contact($r('app.string.contacts_A_two'), $r('app.media.iconB')),
      // app.media.iconC为自定义资源
      new Contact('Angela', $r('app.media.iconC')),
    ],
    key: util.generateRandomUUID(true)
  } as ContactsGroup,
  {
    title: 'B',
    contacts: [
      // app.string.contacts_B_one 资源文件中的value值为'白叶',app.media.iconD为自定义资源
      new Contact($r('app.string.contacts_B_one'), $r('app.media.iconD')),
      // app.string.contacts_B_three 资源文件中的value值为'伯明',app.media.iconE为自定义资源
      new Contact($r('app.string.contacts_B_three'), $r('app.media.iconE'))
    ],
    key: util.generateRandomUUID(true)
  } as ContactsGroup
];

export let contactsGroupsDataSource: ContactsGroupDataSource = new ContactsGroupDataSource(contactsGroups);

@Entry
@Component
export struct StickyHeaderList {
  // 定义分组联系人数据集合contactsGroups数组
  @Builder
  itemHead(text: string) {
    // 列表分组的头部组件,对应联系人分组A、B等位置的组件
    Text(text)
      .fontSize(20)
      .backgroundColor('#fff1f3f5')
      .width('100%')
      .padding(5)
  }
  build() {
    // ...
        List() {
          // 懒加载ListItemGroup,contactsGroups为多个分组联系人contacts和标题title的数据集合
          LazyForEach(contactsGroupsDataSource, (itemGroup: ContactsGroup) => {
            ListItemGroup({ header: this.itemHead(itemGroup.title) }) {
              // 循环渲染ListItem
              if (itemGroup.contacts) {
                LazyForEach(new ContactsGroupDataSource(itemGroup.contacts), (item: Contact) => {
                  ListItem() {
                    Row() {
                      Image(item.icon).width(40).height(40).margin(10)
                      Text(item.name).fontSize(20)
                    }.width('100%').justifyContent(FlexAlign.Start)
                  }
                }, (item: Contact) => JSON.stringify(item))
              }
            }
          }, (itemGroup: ContactsGroup) => JSON.stringify(itemGroup))
        }
        .sticky(StickyStyle.Header) // 设置吸顶,实现粘性标题效果
        // ...
  }
}

弄个height0的header

<header style="height: 0;"></header>

在 ArkUI 中,List 组件本身没有直接的 sticky 属性,但可以试一下通过 ListItemGroup 的 header 属性配合 sticky: StickyStyle.Header 来实现吸顶效果。

去翻翻ListItemGroup的api文档,

在HarmonyOS Next中,使用List组件实现吸顶效果,可通过设置sticky属性实现。将List的子组件ListItemGroup的sticky属性设置为StickyStyle.Header,即可让该组在滚动时固定在顶部。此属性支持Header和Footer两种模式,分别对应顶部和底部固定。

在HarmonyOS Next的ArkUI中,可以通过List组件的sticky属性实现分类标题的“吸顶”效果。该属性属于ListItemGroup组件,而非ListItem

核心实现方式如下:

  1. 数据结构:建议将列表数据组织为二维数组,外层数组代表分组,内层数组代表每个分组下的子项。
  2. 使用ListItemGroup:在List组件内,使用ListItemGroup包裹每个分类(组)。关键点是为ListItemGroup设置sticky属性
  3. 设置sticky属性sticky属性的取值类型为StickyStyle,常用值为:
    • StickyStyle.Header:仅组头吸顶(默认值)。
    • StickyStyle.None:不吸顶。

示例代码结构:

@Entry
@Component
struct Index {
  // 示例:二维数组数据,[分组][子项]
  private data: string[][] = [...];

  build() {
    Column() {
      List({ space: 10 }) {
        ForEach(this.data, (itemGroup: string[], groupIndex: number) => {
          ListItemGroup({ header: this.GroupHeader(groupIndex) }) {
            ForEach(itemGroup, (item: string, itemIndex: number) => {
              ListItem() {
                // 渲染每个子项的内容
                Text(item)
                  .fontSize(16)
                  .padding(10)
              }
            }, (item: string) => item)
          }
          .sticky(StickyStyle.Header) // 关键:设置该分组头部吸顶
        }, (itemGroup: string[]) => JSON.stringify(itemGroup))
      }
    }
  }

  // 分组头部组件
  @Builder
  GroupHeader(index: number) {
    Text(`分类 ${index + 1}`)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
      .backgroundColor(Color.White)
      .width('100%')
      .padding(10)
  }
}

关键说明:

  • sticky属性直接作用于ListItemGroup,设置后该分组的头部(即header属性构建的组件)在滚动时会自动吸顶。
  • 吸顶效果是系统原生行为,性能较好,无需手动计算滚动位置。
  • 当前StickyStyle主要支持Header吸顶。如需更复杂的滚动联动效果(如部分内容吸顶后推挤上一个吸顶标题),需要结合Scrollposition属性进行自定义实现。

因此,针对商品分类列表的需求,使用List + ListItemGroup并设置sticky(StickyStyle.Header)是最简洁直接的实现方案。

回到顶部