HarmonyOS鸿蒙Next中WaterFlow的WaterFlowSections使用分组能力和Repeat的懒加载是不是不兼容?

HarmonyOS鸿蒙Next中WaterFlow的WaterFlowSections使用分组能力和Repeat的懒加载是不是不兼容? 如图:官方demo waterflow

/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { CommonConstants } from '../common/constants/CommonConstants';
import Logger from '../common/utils/Logger';
import { SectionsWaterFlowDataSource } from '../viewmodel/SectionsWaterFlowDataSource';

@Component
struct ReusableFlowItem {
  @State item: number = 0;

  // aboutToReuse(params: Record<string, number>) {
  //   this.item = params.item;
  // }

  build() {
    RelativeContainer() {
      Image($rawfile(`sections/${this.item % 4}.jpg`))
        .objectFit(ImageFit.Cover)
        .width(CommonConstants.FULL_WIDTH)
        .layoutWeight(1)
        .borderRadius($r('app.float.sections_item_radius'))
        .alignRules({
          top: { anchor: '__container__', align: VerticalAlign.Top },
          bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
          left: { anchor: '__container__', align: HorizontalAlign.Start },
          right: { anchor: '__container__', align: HorizontalAlign.End }
        })
        .id('image1')

      Stack() {
      }
      .linearGradient({
        angle: 0,
        colors: [[$r('app.color.linearGradient_first_color'), 0.0],
          [$r('app.color.linearGradient_last_color'), 1.0]]
      })
      .width(CommonConstants.FULL_WIDTH)
      .height($r('app.float.sections_item_blur_height'))
      .borderRadius($r('app.float.sections_item_radius'))
      .hitTestBehavior(HitTestMode.None)
      .alignRules({
        bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
        left: { anchor: '__container__', align: HorizontalAlign.Start },
        right: { anchor: '__container__', align: HorizontalAlign.End }
      })
      .id('mask1')

      Text('NO. ' + (this.item + 1))
        .fontSize($r('app.float.sections_item_text_size'))
        .fontColor(Color.White)
        .alignRules({
          bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
          left: { anchor: '__container__', align: HorizontalAlign.Start }
        })
        .margin({
          left: $r('app.float.sections_item_text_margin_left'),
          bottom: $r("app.float.sections_item_text_margin_bottom")
        })
        .id('text1')
    }
    .width(CommonConstants.FULL_WIDTH)
    .borderRadius($r('app.float.sections_item_radius'))
    .backgroundColor(Color.Gray)
  }
}

@Preview
@Component
export struct SectionsPage {
  @State isRefreshing: boolean = false;
  @State currentItem: number = -1;

  @State minSize: number = CommonConstants.FLOW_ITEM_MIN_HEIGHT;
  @State maxSize: number = CommonConstants.FLOW_ITEM_MAX_HEIGHT;
  scroller: Scroller = new Scroller();
  @State dataArray: number[] = []
  private itemHeightArray: number[] = [];
  @State sections: WaterFlowSections = new WaterFlowSections();
  sectionMargin: Margin = {
    top: 8,
    left: 0,
    bottom: 0,
    right: 0
  };
  oneColumnSection: SectionOptions = {
    itemsCount: 3,
    crossCount: 1,
    columnsGap: 5,
    rowsGap: 10,
    margin: this.sectionMargin,
    onGetItemMainSizeByIndex: (index: number) => {
      return CommonConstants.SECTION1_ITEM_SIZE;
    }
  };
  twoColumnSection: SectionOptions = {
    itemsCount: 2,
    crossCount: 2,
    margin: this.sectionMargin,
    onGetItemMainSizeByIndex: (index: number) => {
      return CommonConstants.SECTION2_ITEM_SIZE;
    }
  };
  dataSection: SectionOptions = {
    itemsCount: 20,
    crossCount: 2,
    margin: this.sectionMargin,
    onGetItemMainSizeByIndex: (index: number) => {
      return this.itemHeightArray[index % CommonConstants.REFRESH_COUNT];
    }
  };

  @Builder
  headerRefresh() {
    Column() {
      LoadingProgress()
        .color(Color.Black)
        .opacity(0.6)
        .width($r('app.float.refresh_loading_width'))
        .height($r('app.float.refresh_loading_height'))
    }
    .justifyContent(FlexAlign.Center)
  }

  refresh() {
    this.currentItem = -1;
    setTimeout(() => {
      //Add new data.
      this.dataArray = [];
      let value = Math.floor(Math.random() * CommonConstants.REFRESH_COUNT);
      for (let i = 0; i < CommonConstants.REFRESH_COUNT; i++) {
        this.dataArray.push(i + value)
      }
      //Update sections itemsCount.
      this.oneColumnSection.itemsCount = 3;
      this.oneColumnSection.crossCount = 1;
      this.twoColumnSection.itemsCount = 2;
      this.twoColumnSection.crossCount = 2;
      this.dataSection.itemsCount = 95;
      this.dataSection.crossCount = 2;
      this.sections.update(0, this.oneColumnSection);
      this.sections.update(1, this.twoColumnSection);
      this.sections.update(2, this.dataSection);
      this.isRefreshing = false;
    }, CommonConstants.REFRESH_TIMEOUT);
  }

  loadMore(last: number) {
    setTimeout(() => {
      let totalCount = this.dataArray.length;
      const index: number = this.dataArray.length;
      const tmpArrays: number[]= []
      if (last + CommonConstants.LOAD_MORE_COUNT >= totalCount) {
        for (let i = 0; i < CommonConstants.LOAD_MORE_COUNT; i++) {
          // this.dataArray.splice(this.dataArray.length, 0, this.dataArray.length);
          tmpArrays.push((index + i))
          // this.dataArray.push(this.dataArray.length)
        }
        this.dataArray = [...this.dataArray,...tmpArrays]
        Logger.error(`dataArray =>${this.dataArray.length}`)
        //Update sections itemsCount.
        this.dataSection.itemsCount += CommonConstants.LOAD_MORE_COUNT;
        this.sections.update(2, this.dataSection);
        Logger.error(`sections =>${this.sections.length}`)
      }
    }, CommonConstants.LOAD_MORE_TIMEOUT);
  }

  getSize() {
    let ret = Math.floor(Math.random() * this.maxSize);
    return (ret > this.minSize ? ret : this.minSize);
  }

  setItemSizeArray() {
    for (let i = 0; i < CommonConstants.REFRESH_COUNT; i++) {
      this.itemHeightArray.push(this.getSize());
    }
  }

  initSections() {
    let sectionOptions: SectionOptions[] = [];
    let count = 0;
    let oneOrTwo = 0;
    // let dataCount = this.dataSource.totalCount();
    let dataCount = this.dataArray.length;
    while (count < dataCount) {
      if (dataCount - count < 96) {
        this.dataSection.itemsCount = dataCount - count;
        sectionOptions.push(this.dataSection);
        break;
      }
      if (oneOrTwo++ % 2 === 0) {
        sectionOptions.push(this.oneColumnSection);
        count += this.oneColumnSection.itemsCount;
      } else {
        sectionOptions.push(this.twoColumnSection);
        count += this.twoColumnSection.itemsCount;
      }
    }
    this.sections.splice(0, 0, sectionOptions);
  }

  removeItem(item: number): void {
    let index = this.dataArray.indexOf(item);
    this.dataArray.splice(index, 1);
    const sections: Array<SectionOptions> = this.sections.values();
    let newSection: SectionOptions;
    let tmpIndex = 0;
    let sectionIndex = 0;
    for(let i = 0; i < sections.length; i++) {
      tmpIndex += sections[i].itemsCount;
      if (index < tmpIndex) {
        sectionIndex = i;
        break;
      }
    }
    newSection = sections[sectionIndex];
    newSection.itemsCount -= 1;
    if (newSection.crossCount && newSection.crossCount > newSection.itemsCount) {
      newSection.crossCount = newSection.itemsCount;
    }
    this.sections.update(sectionIndex, newSection);
  }

  aboutToAppear() {
    for (let i = 0; i < CommonConstants.REFRESH_COUNT; i++) {
      this.dataArray.push(i);
    }
    this.setItemSizeArray();
    this.initSections();
  }

  build() {
    Column({ space: 0 }) {
      Refresh({ refreshing: $$this.isRefreshing, builder: this.headerRefresh()}) {
        WaterFlow({ scroller: this.scroller, sections: this.sections}) {
          // LazyForEach(this.dataSource, (item: number) => {
          //   FlowItem() {
          //     this.buildItem(item)
          //   }
          //   .transition({ type: TransitionType.Delete, opacity: 0 })
          //   .priorityGesture(LongPressGesture()
          //     .onAction(() => {
          //       this.currentItem = item;
          //     }))
          //   .width(CommonConstants.FULL_WIDTH)
          //   .borderRadius($r('app.float.sections_item_radius'))
          //   .backgroundColor(Color.Gray)
          // }, (item: string) => item)

          Repeat(this.dataArray)
            .each((repeatItem: RepeatItem<number>) =>{
              FlowItem() {
                this.buildItem(repeatItem.item)
              }
              .transition({ type: TransitionType.Delete, opacity: 0 })
              .priorityGesture(LongPressGesture()
                .onAction(() => {
                  this.currentItem = repeatItem.item;
                }))
              .width(CommonConstants.FULL_WIDTH)
              .borderRadius($r('app.float.sections_item_radius'))
              .backgroundColor(Color.Gray)
            })
            .virtualScroll({ totalCount: this.dataArray.length })
        }
        .cachedCount(CommonConstants.CACHED_COUNT)
        .columnsGap($r('app.float.sections_margin'))
        .rowsGap($r('app.float.sections_margin'))
        //Fix last item not full display.
        .padding({ bottom: $r('app.float.water_flow_margin_bottom') })
        .width(CommonConstants.FULL_WIDTH)
        .height(CommonConstants.FULL_HEIGHT)
        .layoutWeight(1)
        //For better experience, pre load data.
        .onScrollIndex((first: number, last: number) => {
          this.loadMore(last);
        })
      }
      .refreshOffset(CommonConstants.REFRESH_OFFSET)
      .onRefreshing(() => {
        this.refresh();
      })
    }
  }

  @Builder
  buildItem(item: number) {
    Stack() {
      Row() {
        Button($r('app.string.delete'))
          .fontColor(Color.Red)
          .backgroundColor(Color.White)
          .onClick(() => {
            this.getUIContext().animateTo({ duration: CommonConstants.DELETE_ANIMATION_TIME }, () => {
              this.removeItem(item);
            });
          });
      }
      .width(CommonConstants.FULL_WIDTH)
      .height(CommonConstants.FULL_HEIGHT)
      .borderRadius($r('app.float.sections_item_radius'))
      .justifyContent(FlexAlign.Center)
      .zIndex(1)
      .visibility(this.currentItem === item ? Visibility.Visible : Visibility.Hidden)
      .backgroundColor($r('app.color.delete_background_color'));

      ReusableFlowItem({ item: item });
    }
  }
}

更多关于HarmonyOS鸿蒙Next中WaterFlow的WaterFlowSections使用分组能力和Repeat的懒加载是不是不兼容?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

开发者你好,Repeat需要配合状态管理V2使用,由于WaterFlowSections定义在框架中,开发者无法使用@Trace标注其属性,此时可以使用makeObserved替代。

【修改建议】

一般情况下可以使用@Trace装饰器修饰复杂对象的内部属性达到观察效果,但是自定义sections的类型已经封装好了,无法使用@Trace。此时可以使用工具类UIUtils的makeObserved方法使得复杂对象sections的内部属性可观测。

import { UIUtils } from '@kit.ArkUI'  
sections: WaterFlowSections = UIUtils.makeObserved(new WaterFlowSections())

【常见FAQ】

Q:makeObserve如何在@ComponentV1中使用呢?

A:makeObserved可以用在@Component装饰的自定义组件中,但不能和状态管理V1的状态变量装饰器配合使用,如果一起使用,则会抛出运行时异常。具体可参考makeObserved限制条件

以下是根据你提供的官方demo修改后的代码:

/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { CommonConstants } from '../common/constants/CommonConstants';
import Logger from '../common/utils/Logger';
import { SectionsWaterFlowDataSource } from '../viewmodel/SectionsWaterFlowDataSource';
import { UIUtils } from '@kit.ArkUI';

@Component
struct ReusableFlowItem {
  @State item: number = 0;

  // aboutToReuse(params: Record<string, number>) {
  //   this.item = params.item;
  // }

  build() {
    RelativeContainer() {
      Image($rawfile(`sections/${this.item % 4}.jpg`))
        .objectFit(ImageFit.Cover)
        .width(CommonConstants.FULL_WIDTH)
        .layoutWeight(1)
        .borderRadius($r('app.float.sections_item_radius'))
        .alignRules({
          top: { anchor: '__container__', align: VerticalAlign.Top },
          bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
          left: { anchor: '__container__', align: HorizontalAlign.Start },
          right: { anchor: '__container__', align: HorizontalAlign.End }
        })
        .id('image1')

      Stack() {
      }
      .linearGradient({
        angle: 0,
        colors: [[$r('app.color.linearGradient_first_color'), 0.0],
          [$r('app.color.linearGradient_last_color'), 1.0]]
      })
      .width(CommonConstants.FULL_WIDTH)
      .height($r('app.float.sections_item_blur_height'))
      .borderRadius($r('app.float.sections_item_radius'))
      .hitTestBehavior(HitTestMode.None)
      .alignRules({
        bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
        left: { anchor: '__container__', align: HorizontalAlign.Start },
        right: { anchor: '__container__', align: HorizontalAlign.End }
      })
      .id('mask1')

      Text('NO. ' + (this.item + 1))
        .fontSize($r('app.float.sections_item_text_size'))
        .fontColor(Color.White)
        .alignRules({
          bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
          left: { anchor: '__container__', align: HorizontalAlign.Start }
        })
        .margin({
          left: $r('app.float.sections_item_text_margin_left'),
          bottom: $r("app.float.sections_item_text_margin_bottom")
        })
        .id('text1')
    }
    .width(CommonConstants.FULL_WIDTH)
    .borderRadius($r('app.float.sections_item_radius'))
    .backgroundColor(Color.Gray)
  }
}

@Preview
@ComponentV2
export struct SectionsPage {
  isRefreshing: boolean = false;
  currentItem: number = -1;

  minSize: number = CommonConstants.FLOW_ITEM_MIN_HEIGHT;
  maxSize: number = CommonConstants.FLOW_ITEM_MAX_HEIGHT;
  scroller: Scroller = new Scroller();
  @Local dataArray: number[] = []
  private itemHeightArray: number[] = [];
  sections: WaterFlowSections = UIUtils.makeObserved(new WaterFlowSections());
  sectionMargin: Margin = {
    top: 8,
    left: 0,
    bottom: 0,
    right: 0
  };
  oneColumnSection: SectionOptions = {
    itemsCount: 3,
    crossCount: 1,
    columnsGap: 5,
    rowsGap: 10,
    margin: this.sectionMargin,
    onGetItemMainSizeByIndex: (index: number) => {
      return CommonConstants.SECTION1_ITEM_SIZE;
    }
  };
  twoColumnSection: SectionOptions = {
    itemsCount: 2,
    crossCount: 2,
    margin: this.sectionMargin,
    onGetItemMainSizeByIndex: (index: number) => {
      return CommonConstants.SECTION2_ITEM_SIZE;
    }
  };
  dataSection: SectionOptions = {
    itemsCount: 20,
    crossCount: 2,
    margin: this.sectionMargin,
    onGetItemMainSizeByIndex: (index: number) => {
      return this.itemHeightArray[index % CommonConstants.REFRESH_COUNT];
    }
  };

  @Builder
  headerRefresh() {
    Column() {
      LoadingProgress()
        .color(Color.Black)
        .opacity(0.6)
        .width($r('app.float.refresh_loading_width'))
        .height($r('app.float.refresh_loading_height'))
    }
    .justifyContent(FlexAlign.Center)
  }

  refresh() {
    this.currentItem = -1;
    setTimeout(() => {
      //Add new data.
      this.dataArray = [];
      let value = Math.floor(Math.random() * CommonConstants.REFRESH_COUNT);
      for (let i = 0; i < CommonConstants.REFRESH_COUNT; i++) {
        this.dataArray.push(i + value)
      }
      //Update sections itemsCount.
      this.oneColumnSection.itemsCount = 3;
      this.oneColumnSection.crossCount = 1;
      this.twoColumnSection.itemsCount = 2;
      this.twoColumnSection.crossCount = 2;
      this.dataSection.itemsCount = 95;
      this.dataSection.crossCount = 2;
      this.sections.update(0, this.oneColumnSection);
      this.sections.update(1, this.twoColumnSection);
      this.sections.update(2, this.dataSection);
      this.isRefreshing = false;
    }, CommonConstants.REFRESH_TIMEOUT);
  }

  loadMore(last: number) {
    setTimeout(() => {
      let totalCount = this.dataArray.length;
      const index: number = this.dataArray.length;
      const tmpArrays: number[]= []
      if (last + CommonConstants.LOAD_MORE_COUNT >= totalCount) {
        for (let i = 0; i < CommonConstants.LOAD_MORE_COUNT; i++) {
          // this.dataArray.splice(this.dataArray.length, 0, this.dataArray.length);
          tmpArrays.push((index + i))
          // this.dataArray.push(this.dataArray.length)
        }
        this.dataArray = [...this.dataArray,...tmpArrays]
        Logger.error(`dataArray =>${this.dataArray.length}`)
        //Update sections itemsCount.
        this.dataSection.itemsCount += CommonConstants.LOAD_MORE_COUNT;
        this.sections.update(2, this.dataSection);
        Logger.error(`sections =>${this.sections.length}`)
      }
    }, CommonConstants.LOAD_MORE_TIMEOUT);
  }

  getSize() {
    let ret = Math.floor(Math.random() * this.maxSize);
    return (ret > this.minSize ? ret : this.minSize);
  }

  setItemSizeArray() {
    for (let i = 0; i < CommonConstants.REFRESH_COUNT; i++) {
      this.itemHeightArray.push(this.getSize());
    }
  }

  initSections() {
    let sectionOptions: SectionOptions[] = [];
    let count = 0;
    let oneOrTwo = 0;
    // let dataCount = this.dataSource.totalCount();
    let dataCount = this.dataArray.length;
    while (count < dataCount) {
      if (dataCount - count < 96) {
        this.dataSection.itemsCount = dataCount - count;
        sectionOptions.push(this.dataSection);
        break;
      }
      if (oneOrTwo++ % 2 === 0) {
        sectionOptions.push(this.oneColumnSection);
        count += this.oneColumnSection.itemsCount;
      } else {
        sectionOptions.push(this.twoColumnSection);
        count += this.twoColumnSection.itemsCount;
      }
    }
    this.sections.splice(0, 0, sectionOptions);
  }

  removeItem(item: number): void {
    let index = this.dataArray.indexOf(item);
    this.dataArray.splice(index, 1);
    const sections: Array<SectionOptions> = this.sections.values();
    let newSection: SectionOptions;
    let tmpIndex = 0;
    let sectionIndex = 0;
    for(let i = 0; i < sections.length; i++) {
      tmpIndex += sections[i].itemsCount;
      if (index < tmpIndex) {
        sectionIndex = i;
        break;
      }
    }
    newSection = sections[sectionIndex];
    newSection.itemsCount -= 1;
    if (newSection.crossCount && newSection.crossCount > newSection.itemsCount) {
      newSection.crossCount = newSection.itemsCount;
    }
    this.sections.update(sectionIndex, newSection);
  }

  aboutToAppear() {
    for (let i = 0; i < CommonConstants.REFRESH_COUNT; i++) {
      this.dataArray.push(i);
    }
    this.setItemSizeArray();
    this.initSections();
  }

  build() {
    Column({ space: 0 }) {
      Refresh({ refreshing: $$this.isRefreshing, builder: this.headerRefresh()}) {
        WaterFlow({ scroller: this.scroller, sections: this.sections}) {
          // LazyForEach(this.dataSource, (item: number) => {
          //   FlowItem() {
          //     this.buildItem(item)
          //   }
          //   .transition({ type: TransitionType.Delete, opacity: 0 })
          //   .priorityGesture(LongPressGesture()
          //     .onAction(() => {
          //       this.currentItem = item;
          //     }))
          //   .width(CommonConstants.FULL_WIDTH)
          //   .borderRadius($r('app.float.sections_item_radius'))
          //   .backgroundColor(Color.Gray)
          // }, (item: string) => item)

          Repeat(this.dataArray)
            .each((repeatItem: RepeatItem<number>) =>{
              FlowItem() {
                this.buildItem(repeatItem.item)
              }
              .transition({ type: TransitionType.Delete, opacity: 0 })
              .priorityGesture(LongPressGesture()
                .onAction(() => {
                  this.currentItem = repeatItem.item;
                }))
              .width(CommonConstants.FULL_WIDTH)
              .borderRadius($r('app.float.sections_item_radius'))
              .backgroundColor(Color.Gray)
            })
            .virtualScroll({ totalCount: this.dataArray.length })
        }
        .cachedCount(CommonConstants.CACHED_COUNT)
        .columnsGap($r('app.float.sections_margin'))
        .rowsGap($r('app.float.sections_margin'))
        //Fix last item not full display.
        .padding({ bottom: $r('app.float.water_flow_margin_bottom') })
        .width(CommonConstants.FULL_WIDTH)
        .height(CommonConstants.FULL_HEIGHT)
        .layoutWeight(1)
        //For better experience, pre load data.
        .onScrollIndex((first: number, last: number) => {
          this.loadMore(last);
        })
      }
      .refreshOffset(CommonConstants.REFRESH_OFFSET)
      .onRefreshing(() => {
        this.refresh();
      })
    }
  }

  @Builder
  buildItem(item: number) {
    Stack() {
      Row() {
        Button($r('app.string.delete'))
          .fontColor(Color.Red)
          .backgroundColor(Color.White)
          .onClick(() => {
            this.getUIContext().animateTo({ duration: CommonConstants.DELETE_ANIMATION_TIME }, () => {
              this.removeItem(item);
            });
          });
      }
      .width(CommonConstants.FULL_WIDTH)
      .height(CommonConstants.FULL_HEIGHT)
      .borderRadius($r('app.float.sections_item_radius'))
      .justifyContent(FlexAlign.Center)
      .zIndex(1)
      .visibility(this.currentItem === item ? Visibility.Visible : Visibility.Hidden)
      .backgroundColor($r('app.color.delete_background_color'));

      ReusableFlowItem({ item: item });
    }
  }
}

更多关于HarmonyOS鸿蒙Next中WaterFlow的WaterFlowSections使用分组能力和Repeat的懒加载是不是不兼容?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


WaterFlowSections中splice全部和update会有性能区分吗

如果加上懒加载能力,之后分页面,就会报错

[(100000:100000:scope)] Children count = 100 and doesn't match the number provided in Sections, which is 120.

在HarmonyOS Next中,WaterFlowSections的分组能力与Repeat的懒加载机制存在不兼容性。WaterFlowSections要求数据在初始化时完全确定分组结构,而Repeat的懒加载会动态加载数据项,导致分组无法预先完整构建。这种设计差异使得两者无法协同工作,需避免在分组场景下使用懒加载的Repeat。

在HarmonyOS Next中,WaterFlowSections的分组能力与Repeat的懒加载确实存在兼容性问题。从您提供的代码可以看出:

  1. Repeat组件通过virtualScroll实现懒加载,但这种方式与WaterFlowSections的分组机制存在冲突
  2. 数据更新问题:当使用sections.update()更新分组配置时,Repeat组件可能无法正确响应数据变化
  3. 性能影响:Repeat的虚拟滚动与WaterFlowSections的分组布局计算会产生双重开销

建议解决方案

  • 使用LazyForEach替代Repeat组件,LazyForEach与WaterFlowSections的兼容性更好
  • 或者考虑使用单一的数据源管理方式,避免混合使用不同渲染策略

代码中注释掉的LazyForEach部分实际上是更推荐的实现方式,建议恢复使用LazyForEach来确保分组功能正常工作。

回到顶部