HarmonyOS Next中 在List的onScrollIndex方法中调用onDataReloaded有产生屏幕闪烁是怎么回事?

代码如下:



class MyDataSource extends BasicDataSource {
  private dataArray: string[] = [];

  public totalCount(): number {
    return this.dataArray.length;
  }

  public getData(index: number): string {
    return this.dataArray[index];
  }

  public addData(index: number, data: string): void {
    this.dataArray.splice(index, 0, data);
    this.notifyDataAdd(index);
  }

  public pushData(data: string): void {
    this.dataArray.push(data);
    this.notifyDataAdd(this.dataArray.length - 1);
  }

  public deleteData(index: number): void {
    this.dataArray.splice(index, 1);
    this.notifyDataDelete(index);
  }

  public changeData(index: number): void {
    this.notifyDataChange(index);
  }

  operateData():void {
    const totalCount = this.dataArray.length;
    const batch=5;
    for (let i = totalCount; i < totalCount + batch; i++) {
      this.dataArray.push(`Hello ${i}`)
    }
    this.notifyDataReload();
  }
}

@Entry
@Component
struct MyComponent {
  private moved: number[] = [];
  private data: MyDataSource = new MyDataSource();

  aboutToAppear() {
    for (let i = 0; i <= 10; i++) {
      this.data.pushData(`Hello ${i}`)
    }
  }

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string, index: number) => {
        ListItem() {
          Row() {
            Text(item)
              .width('100%')
              .height(80)
              .backgroundColor(Color.Gray)
              .onAppear(() => {
                console.info("appear:" + item)
              })
          }.margin({ left: 10, right: 10 })
        }
      }, (item: string) => item)
    }.cachedCount(10)
    .onScrollIndex((start, end, center) => {
      if (end === this.data.totalCount() - 1) {
        console.log('scroll to end')
        this.data.operateData();
      }
    })
  }
}

本文参与了 【 HarmonyOS NEXT 技术问答冲榜,等你来战!】欢迎正在阅读的你也加入。

阅读 155
avatarAI BotBETA
屏幕闪烁的原因是在 `onScrollIndex` 方法中调用 `operateData` 后触发了数据重载(`notifyDataReload`),导致整个列表被重新渲染。在 HarmonyOS 中,当调用 `notifyDataReload` 时,会触发列表的重新布局和渲染,如果这个过程发生在用户滚动列表时,尤其是在接近列表底部时,会导致用户看到明显的闪烁现象。

解决这个问题的一种方法是避免在滚动事件中直接触发数据重载。你可以考虑以下几种策略:

1. **延迟数据加载**:在用户滚动到底部后,使用定时器(如 `setTimeout`)延迟一段时间后再进行数据加载,这样可以在用户停止滚动后再进行数据更新,减少闪烁的可能性。

2. **局部更新**:如果可能,尽量使用局部更新(如 `notifyDataAdd`、`notifyDataDelete`、`notifyDataChange`)而不是整个列表的重载。这样只有受影响的部分会被重新渲染。

3. **优化渲染性能**:确保你的列表项渲染逻辑尽可能高效,避免复杂的计算或大量的 DOM 操作。

4. **用户反馈**:在数据加载时给用户一些视觉或触觉反馈(如显示加载指示器),这样用户就知道正在发生数据更新,而不是因为应用卡顿或闪烁而感到困惑。
1 个回答

用onDatasetChange代替onDataReloaded,不仅可以修复闪屏的问题,还能提升加载性能。



class MyDataSource extends BasicDataSource {
  private dataArray: string[] = [];

  public totalCount(): number {
    return this.dataArray.length;
  }

  public getData(index: number): string {
    return this.dataArray[index];
  }

  public addData(index: number, data: string): void {
    this.dataArray.splice(index, 0, data);
    this.notifyDataAdd(index);
  }

  public pushData(data: string): void {
    this.dataArray.push(data);
    this.notifyDataAdd(this.dataArray.length - 1);
  }

  public deleteData(index: number): void {
    this.dataArray.splice(index, 1);
    this.notifyDataDelete(index);
  }

  public changeData(index: number): void {
    this.notifyDataChange(index);
  }

  operateData():void {
    const totalCount = this.dataArray.length;
    const batch=5;
    for (let i = totalCount; i < totalCount + batch; i++) {
      this.dataArray.push(`Hello ${i}`)
    }
    // 替换 notifyDataReload
    this.notifyDatasetChange([{type:DataOperationType.ADD, index: totalCount-1, count:batch}])
  }
}

@Entry
@Component
struct MyComponent {
  private moved: number[] = [];
  private data: MyDataSource = new MyDataSource();

  aboutToAppear() {
    for (let i = 0; i <= 10; i++) {
      this.data.pushData(`Hello ${i}`)
    }
  }

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string, index: number) => {
        ListItem() {
          Row() {
            Text(item)
              .width('100%')
              .height(80)
              .backgroundColor(Color.Gray)
              .onAppear(() => {
                console.info("appear:" + item)
              })
          }.margin({ left: 10, right: 10 })
        }
      }, (item: string) => item)
    }.cachedCount(10)
    .onScrollIndex((start, end, center) => {
      if (end === this.data.totalCount() - 1) {
        console.log('scroll to end')
        this.data.operateData();
      }
    })
  }
}

本文参与了 【 HarmonyOS NEXT 技术问答冲榜,等你来战!】欢迎正在阅读的你也加入。

logo
HarmonyOS
子站问答
访问
宣传栏