HarmonyOS 加载更多的组件怎么嵌套swiper使用

怎么通过swiper实现加载更多的功能?

HarmonyOS
2024-12-25 12:45:20
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
Excelsior_abit

1、利用parallelGesture和PanGesture绑定拖动触发事件,可实现swiper下拉刷新效果,示例参考:

@Entry
@Component
struct SwiperItemLeak {
  private swiperController: SwiperController = new SwiperController()
  private curSwiperIndex = 0;
  private list: number[] = []
  @State isStopSwiperSlide: boolean = false;
  @State positionY: number = 0;
  private isRefresh: boolean = false;

  aboutToAppear(): void {
    for (let i = 1; i <= 10; i++) {
      this.list.push(i);
    }
  }

  build() {
    Stack({ alignContent: Alignment.TopStart }) {
      Text(this.positionY.toString())
        .width('100%')
        .height('10%')
        .textAlign(TextAlign.Center)
        .fontSize(30)
      Swiper(this.swiperController) {
        ForEach(this.list, (item: number) => {
          Text(item.toString())
            .width('100%')
            .height('100%')
            .backgroundColor(0xAFEEEE * ((item + 1) / 0x0f))
            .textAlign(TextAlign.Center)
            .fontSize(30)
        })
      }
      .vertical(true)
      .width("100%")
      .height("100%")
      .cachedCount(3)
      .index(0)
      .autoPlay(false)
      .indicator(false)
      .effectMode(EdgeEffect.None)
      .loop(false)
      .duration(100)
      .disableSwipe(this.isStopSwiperSlide)
      .displayCount(1)
      .itemSpace(0)
      .curve(Curve.Linear)
      .backgroundColor(Color.Red)
      .position({ y: this.positionY })
      .onChange((index: number) => {
        console.info(index.toString())
        this.curSwiperIndex = index;
      })
      .parallelGesture(
        PanGesture()
          .onActionStart((event: GestureEvent) => {
          })
          .onActionUpdate((event: GestureEvent) => {
            if (event && this.curSwiperIndex == 0) {
              if (event.offsetY > 0) {
                this.positionY = event.offsetY;
                this.isStopSwiperSlide = true;
                this.isRefresh = true;
              } else {
                this.positionY = 0;
                this.isStopSwiperSlide = false;
                this.isRefresh = false;
              }
            }
          })
          .onActionEnd(() => {
            if (this.isRefresh) {
              setTimeout(() => {
                this.isStopSwiperSlide = false;
                this.positionY = 0;
                this.isRefresh = false;
              }, 1000);
            }
          })
      )
    }.width('100%').height("100%").backgroundColor(Color.Pink)
  }
}

2、上拉加载,参考示例:

import { CommonDataSource } from './CommonDataSource'
import { VideoComponent } from './AvPlayerComponent'

@Entry
@Component
struct VideoPlayerDemoPage {
  controller: SwiperController = new SwiperController()
  dataSource = new CommonDataSource<VideoItem>()
  @State currentIndex: number = 0
  @State total: number = 0
  @State isShowRefresh: boolean = false
  aboutToAppear(): void {
    this.dataSource.setData(allData)
  }

  onPageShow(): void {
    this.total = this.dataSource.totalCount()
  }

  build() {
    Flex({ direction: FlexDirection.Column }) {
      Swiper(this.controller) {
        LazyForEach(this.dataSource, (item: VideoItem, index: number) => {
          VideoComponent({ item: item, index, currentIndex: this.currentIndex })
        })
      }
      .height('100%')
      .width('100%')
      .vertical(true)
      .indicator(false)
      .cachedCount(3)
      .loop(false)
      .duration(200)
      .curve(Curve.EaseOut)
      .onChange((index: number) => {
        this.currentIndex = index
        console.log(`result zj ==> ${index}`)
      })
      .onAnimationEnd(() => {
        console.log(`result zj ==> ${JSON.stringify('onAnimationEnd')}`);
        if (this.total === this.currentIndex + 1 && this.isShowRefresh) {
          setTimeout(() => {
            let nItem: VideoItem = new VideoItem()
            nItem.imgUrl = $r("app.media.foreground")
            nItem.videoUrl = 'xxx'
            nItem.imgUrl = '我们只是拿某站的数据进行一下测试'
            this.dataSource.addData(this.currentIndex + 1, nItem)
            this.isShowRefresh = false
            this.total = this.dataSource.totalCount()
          }, 500)
        }
      })
      .onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
        if (this.total === index + 1 && extraInfo.currentOffset < -70) {
          this.isShowRefresh = true
        }
      })


      if (this.isShowRefresh) {
        Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
          LoadingProgress().width(50)
          Text('上拉加载')
        }
        .width('100%')
      }
    }
  }
}

@Observed
class VideoItem {
  videoUrl: string = ''
  imgUrl: ResourceStr = ''
  title: string = ""
}

const allData: VideoItem[] = [
  {
    imgUrl: $r("app.media.foreground"),
    title: 'ArkTS提供了简洁自然的声明式语法、组件化机制、数据-UI自动关联等能力,实现了贴近自然语言,书写效率更高的编程方式,为开发者带来易学、易懂、简洁开发的优质体验。',
    videoUrl: 'xxx'
  },
]
//CommonDataSource.ets文件
export class CommonDataSource<T> implements IDataSource {
  private listeners: DataChangeListener[] = [];
  originDataArray: T[] = [];

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

  getAllData(): T[] {
    return this.originDataArray
  }

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

  addData(index: number, data: T): void {
    this.originDataArray.splice(index, 0, data);
    this.notifyDataAdd(index);
  }

  pushData(data: T): void {
    this.originDataArray.push(data);
    this.notifyDataAdd(this.originDataArray.length - 1);
  }

  pushDataArray(...items: T[]): void {
    for (let data of items) {
      this.originDataArray.push(data);
      this.notifyDataAdd(this.originDataArray.length - 1);
    }
  }

  deleteDataUseContent(data: T): void {
    let delIndex: number = -1
    for (let index = 0; index < this.originDataArray.length; index++) {
      const element = this.originDataArray[index];
      if (data === element) {
        delIndex = index
      }
    }
    if (delIndex != -1) {
      this.deleteData(delIndex)
    }
  }

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

  clear() {
    this.originDataArray.splice(0, this.originDataArray.length)
    this.listeners.forEach(listener => {
      listener.onDataDelete(0)
    })
  }

  setData(dataArray?: T[]) {
    if (dataArray) {
      this.originDataArray = dataArray
    } else {
      this.originDataArray = []
    }
    this.notifyDataReload()
  }

  refreshDataByIndex(start: number, end: number, dataArray: T[]) {
    this.originDataArray.splice(start, end - start, ...dataArray);
    this.notifyDataReload()
  }

  changeData(index: number, data: T): void {
    this.originDataArray.splice(index, 1, data);
    this.notifyDataChange(index);
  }

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

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

  notifyDataReload() {
    this.listeners.forEach(listener => {
      listener.onDataReloaded();
    })
  }

  notifyDataAdd(index: number) {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index);
    })
  }

  notifyDataMove(from: number, to: number) {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to);
    })
  }

  notifyDataDelete(index: number) {
    this.listeners.forEach(listener => {
      listener.onDataDelete(index);
    })
  }

  notifyDataChange(index: number) {
    this.listeners.forEach(listener => {
      listener.onDataChange(index);
    })
  }
}
//AvPlayerComponent.ets文件
import window from '@ohos.window';
import { BusinessError } from '@ohos.base';
import { AVPlayerDemo } from './AVPlayerDemo';

@Observed
class VideoItem {
  videoUrl: string = ''
  imgUrl: ResourceStr = ''
  title: string = ""
}

export class myVideoSourceDate implements IDataSource {
  videoList: VideoItem[] = [];

  constructor(videoList: VideoItem[]) {
    this.videoList = videoList;
  }

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

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

  registerDataChangeListener(listener: DataChangeListener): void {
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
  }
}


@Component
export struct VideoComponent {
  @ObjectLink item: VideoItem;
  index: number = -1;
  mXComponentController: XComponentController = new XComponentController();
  @State player_changed: boolean = false;
  player?: AVPlayerDemo;
  @State playIng: boolean = false
  @Prop currentIndex: number

  aboutToDisappear(): void {
    if (this.player) {
      this.player.release()
    }
  }

  build() {
    Stack({ alignContent: Alignment.Bottom }) {
      Stack() {
        if (this.index === this.currentIndex) {
          XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.mXComponentController })
            .onLoad(() => {
              this.player = new AVPlayerDemo();
              this.player.setSurfaceID(this.mXComponentController.getXComponentSurfaceId());
              this.player.avPlayerLiveDemo(0, this.item.videoUrl)
            })
            .width('100%')
            .aspectRatio(1)
        }

        Image(this.item.imgUrl)
          .width(this.index === this.currentIndex ? 0 : '100%')
          .aspectRatio(1.4)
          .animation({
            duration: 300
          })
        if (!this.playIng) {
          Row() {
            Image($r('app.media.app_icon'))
              .width(100)
              .height(100)
              .fillColor("#9d9393")
          }.width('100%')
          .justifyContent(FlexAlign.Center)
          .onClick(() => {
            this.player?.play()
            this.playIng = true
          })
        }
      }
      .backgroundColor(Color.Black)
      .height('100%')
      .width('100%')

      Text(this.item.title)
        .fontColor(Color.White)
        .width('100%')
        .padding(20)
        .fontSize(20)
        .height(150)
        .lineHeight(28)
        .fontWeight(FontWeight.Bold)
        .textOverflow({
          overflow: TextOverflow.Ellipsis
        })
    }
    .height('100%')
  }
}
//AVPlayerDemo.ets文件
import media from '@ohos.multimedia.media';
import { BusinessError } from '@ohos.base';
import { ifaa } from '@kit.OnlineAuthenticationKit';

export class AVPlayerDemo {
  private count: number = 0;
  private surfaceID: string = ''; // surfaceID用于播放画面显示,具体的值需要通过Xcomponent接口获取,相关文档链接见上面Xcomponent创建方法。
  private isSeek: boolean = true; // 用于区分模式是否支持seek操作。
  private avPlayer?: media.AVPlayer;

  setSurfaceID(surface_id: string) {
    this.surfaceID = surface_id;
  }

  // 注册avplayer回调函数。
  setAVPlayerCallback(avPlayer: media.AVPlayer) {
    this.avPlayer = avPlayer
    // seek操作结果回调函数。
    avPlayer.on('seekDone', (seekDoneTime: number) => {
      console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
    })
    // error回调监听函数,当avplayer在操作过程中出现错误时,调用reset接口触发重置流程。
    avPlayer.on('error', (err: BusinessError) => {
      avPlayer.reset();
    })
    // 状态机变化回调函数。
    avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
      switch (state) {
        case 'idle': // 成功调用reset接口后触发该状态机上报。
          avPlayer.release(); // 调用release接口销毁实例对象。
          break;
        case 'initialized': // avplayer 设置播放源后触发该状态上报。
          avPlayer.surfaceId = this.surfaceID; // 设置显示画面,当播放的资源为纯音频时无需设置。
          avPlayer.prepare();
          break;
        case 'prepared': // prepared调用成功后上报该状态机。
          if (this.count === 0) {
            avPlayer.play(); // 调用播放接口开始播放。
          } else if (this.count === 1) {
            avPlayer.surfaceId = this.surfaceID;
            avPlayer.seek(avPlayer.currentTime); // seek到视频末尾。
            avPlayer.play();
          }
          break;
        case 'playing': // play成功调用后触发该状态机上报。
          break;
        case 'paused': // pause成功调用后触发该状态机上报。
          avPlayer.play(); // 再次播放接口开始播放。
          break;
        case 'completed': //播放接口后触发该状态机上报。
          console.info('AVPlayer state paused called.');
          avPlayer.stop(); // 调用播放接口接口。
          break;
        case 'stopped': // stop接口后触发该状态机上报。
          avPlayer.reset(); // 调用reset接口初始化avplayer状态。
          break;
        case 'released': //播放接口后触发该状态机上报。
          break;
        default:
          break;
      }
    })
  }

  play() {
    this.avPlayer?.play();
  }

  release() {
    this.avPlayer?.release();
  }

  // 通过url设置网络地址来实现播放直播码流。
  async avPlayerLiveDemo(count: number, url ?: string) {
    this.count = count
    // async avPlayerLiveDemo(){
    // 创建avPlayer实例对象
    let avPlayer: media.AVPlayer = await media.createAVPlayer();
    // 创建状态机变化回调函数。
    this.setAVPlayerCallback(avPlayer);
    this.isSeek = false; // 不支持seek操作。
    if (this.count !== 0) {
      this.isSeek = true; // 不支持seek操作。
    }
    avPlayer.url = url;
  }
}
分享
微博
QQ
微信
回复
2024-12-25 15:44:25
相关问题
HarmonyOS swiper实现上拉加载更多
89浏览 • 1回复 待解决
HarmonyOS Swiper嵌套RichEditor问题
167浏览 • 1回复 待解决
Swiper 组件嵌套图片刷新数据会闪烁
1593浏览 • 1回复 待解决
HarmonyOS 上拉加载更多
177浏览 • 1回复 待解决
HarmonyOS swiper组件使用问题
564浏览 • 1回复 待解决
HarmonyOS 下拉聊天数据加载更多实现
269浏览 • 1回复 待解决
刷新列表加载更多问题
590浏览 • 1回复 待解决
使用swiper组件实现viewPager效果
1764浏览 • 1回复 待解决
HarmonyOS Web组件和List嵌套使用问题
716浏览 • 1回复 待解决