# Swiper组件左右滑动加载更多数据

#### 问题现象

使用Swiper组件动态加载数据：

*   当用户从第一页向右滑动时，在数据列表的最前面添加新数据。
*   当用户从最后一页向左滑动时，在数据列表的最后面添加新数据。

#### 效果预览

#### 背景知识

*   在Swiper组件中，当页面切换时会触发onAnimationStart回调函数，用于监听动画的开始事件。该回调函数可提供当前页码index、目标页码targetIndex以及额外信息extraInfo，可用于判断滑动方向。
*   cryptoFramework：对于安全要求比较高的场景，推荐使用加解密算法库框架@ohos.security.cryptoFramework包生成安全随机数。

#### 解决方案

在Swiper组件的onAnimationStart回调中，通过index和targetIndex判断滑动方向，并在相应条件下加载新数据：

*   当index === 0且targetIndex === 0时，表示从第一页向右滑动，此时在数据列表的最前面添加新数据。
*   当index === this.data.totalCount() - 1时，表示从最后一页向左滑动，此时在数据列表的最后面添加新数据。

完整示例参考如下：

```
import cryptoFramework from '@ohos.security.cryptoFramework';

// 数据源，支持对数据的增删改查，并通知UI更新
class MyDataSource implements IDataSource {
  private list: number[] = [];
  private listeners: DataChangeListener[] = [];

  constructor(list: number[]) {
    this.list = list;
  }

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

  getData(index: number): number {
    return this.list[index];
  }

  // 数组末尾添加数据
  pushData(element: number) {
    this.list.push(element);
    this.notifyDataReload();
  }

  // 数组开头添加数据
  unshiftData(element: number) {
    this.list.unshift(element);
    this.notifyDataAdd(0);
  }

  deleteData(index: number) {
    this.list.splice(index, 1);
    this.notifyDataReload();
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      console.info('add listener');
      this.listeners.push(listener);
    }
  }

  unregisterDataChangeListener(listener: DataChangeListener) {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      console.info('remove listener');
      this.listeners.splice(pos, 1);
    }
  }

  // 通知LazyForEach组件需要重载所有子组件
  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded();
    });
  }

  // 通知LazyForEach组件需要在index对应索引处添加子组件
  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
    });
  }

  // 通知LazyForEach组件在index对应索引处数据有变化，需要重建该子组件
  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataChange(index);
    });
  }

  // 通知LazyForEach组件需要在index对应索引处删除该子组件
  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataDelete(index);
    });
  }

  // 通知LazyForEach组件将from索引和to索引处的子组件进行交换
  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to);
    });
  }
}

@Entry
@Component
struct SwiperExample {
  private swiperController: SwiperController = new SwiperController();
  private data: MyDataSource = new MyDataSource([]);

  aboutToAppear(): void {
    let list: number[] = [];
    for (let i = 1; i <= 10; i++) {
      list.push(i);
    }
    this.data = new MyDataSource(list);
  }

  build() {
    Column({ space: 5 }) {
      Swiper(this.swiperController) {
        LazyForEach(this.data, (item: string) => {
          Text(item.toString())
            .width('90%')
            .height(160)
            .backgroundColor(0xAFEEEE)
            .textAlign(TextAlign.Center)
            .fontSize(30);
        }, (item: string) => item);
      }
      .cachedCount(2)
      .index(0)
      .loop(false)
      .itemSpace(5)
      .curve(Curve.Linear)
      .onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
        console.info('extraInfo', extraInfo);
        // 下标为0时，向右滑动，模拟拉取新数据
        if (index === 0 && targetIndex === 0 && extraInfo.currentOffset > 0) {
          let rand = cryptoFramework.createRandom();
          // 设置生成随机数的字节长度为1
          let randData = rand.generateRandomSync(1);
          // 自定义范围(0-10之内)
          let num: number = Math.round(randData.data[0] * 10 / 255);
          this.data.unshiftData(num);
          this.swiperController.changeIndex(1);
        }
        // 下标为数组最后一个时，向左滑动，模拟拉取新数据
        if (index === this.data.totalCount() - 1 && targetIndex === index && extraInfo.currentOffset < 0) {
          let rand = cryptoFramework.createRandom();
          let randData = rand.generateRandomSync(1);
          let num: number = Math.round(randData.data[0] * 10 / 255);
          this.data.pushData(num);
        }
      })
      .onAnimationEnd((index: number, extraInfo: SwiperAnimationEvent) => {
        console.info(`index:\n${index}`);
        console.info(`velocity:\n${extraInfo.velocity}`);
        console.info(`target offset:\n${extraInfo.targetOffset}`);
        console.info(`current offset::\n${extraInfo.currentOffset}`);
      })
      .maintainVisibleContentPosition(true);

      Row({ space: 5 }) {
        Button('FAST 0')
          .onClick(() => {
            this.swiperController.changeIndex(0, SwiperAnimationMode.FAST_ANIMATION);
          });
      };

      Row() {
        Button('FAST LAST')
          .onClick(() => {
            this.swiperController.changeIndex(this.data.totalCount() - 1, SwiperAnimationMode.FAST_ANIMATION);
          });
      };

      Row() {
        Button('顶部添加数据')
          .onClick(() => {
            let rand = cryptoFramework.createRandom();
            let randData = rand.generateRandomSync(1);
            let num: number = Math.round(randData.data[0] * 10 / 255);
            this.data.unshiftData(num);
          });
      };

      Row() {
        Button('尾部添加数据')
          .onClick(() => {
            let rand = cryptoFramework.createRandom();
            let randData = rand.generateRandomSync(1);
            let num: number = Math.round(randData.data[0] * 10 / 255);
            this.data.pushData(num);
          });
      };

      Row() {
        Button('删除第一个')
          .onClick(() => {
            this.data.deleteData(0);
          });
      };
    }.width('100%');
  }
}
```