HarmonyOS Hongmeng study notes (15) Swiper realizes the effect of vibrato switching video playback

1. Project structure

The initial use of the Swiper control was written earlier . This article combines @Link , @State , @Watch to achieve an effect similar to vibrato sliding video playback. The source code address of this article is Swiper actual combat .
The project structure is as shown in the figure below:
insert image description here
it PageVideo.etsis the home page of the APP, which is used to provide a list of video playback. PlayView.etsIt is a video player that PageVideo.etsswitches videos with scrolling to notify PlayView.etspausing and starting video playback. VideoItem.ets contains video information, such as video playback address and so on.

2. Brief description of PageVideo and PlayView

2.1 Use of @State variables

PageVideo@StateTwo modified variables are provided : pageShowand number, when these two states change, PlayViewthe player will be notified to adjust.

@Entry
@Component
export struct PageVideo {
    
    
  @State videoArray: Array<VideoItem> = initializeOnStartup() // 数据源

  //当切换视频的时候,会通知PlayView播放当前的视频,同时关闭上一个视频
  @State index: number = 0 // 当前滑动的索引位置
  @State pageShow: boolean = false // 当前页面是否可见,仅对@Entry修饰的主页面PageVideo而言,子组件需要用@Watch监听该状态
}  

2.2 Use of @Link and @Watch variables

So PlayViewhow do you perceive that these two states have changed? At this point, @Linkthe label plays a role. PlayViewThe code is as follows:

@Component
export struct PlayView {
    
    
  // 四条控制页面可见、页面不可见的控制
  private isShow: boolean = false // 是否是可见状态
  @Link @Watch("needPageShow") index: number // 监听父组件索引index状态变化, 不能在组件内部进行初始化
  @Link @Watch("needPageShow") pageShow: boolean // 监听父组件是否可见pageShow状态变化, 不能在组件内部进行初始化
 }

Among them, the method defined by the @Watch tag is also used needPageShow. When the value of number and pageShow changes, this method will be called to control the video to pause the previous one and play the current video:


  // 监听父组件index、pageShow属性变化就会触发的方法,@Watch
  needPageShow() {
    
    
    console.log("playView*** needPageShow")
    if (this.pageShow) {
    
     // 页面可见时触发
      if (this.position == this.index) {
    
     // 判断index与当前所在位置是否相同
        this.isShow = true;
        this.onPageShow()
      } else {
    
    
        if (this.isShow) {
    
     // 已经是可见的状态改为不可见,并触发不可见方法回调
          this.isShow = false;
          this.onPageSwiperHide()
        }
      }
    } else {
    
     // 页面不可见触发
      if (this.position == this.index) {
    
    
        if (this.isShow) {
    
     // 已经是可见的状态改为不可见,并触发不可见方法回调
          this.isShow = false;
          this.onPageHide()
        }
      }
    }
  }

2.3, the use of Swiper and the initialization of PlayView

In PlayVideo, Swiperthe control is initialized according to the number of videos, and the sub-control of the control is PlayView. Note that when initializing PlayView, it needs to be modified with $ when initializing the @Link modified variable.

 build() {
    
    
    Column() {
    
    
      Swiper() {
    
    
        ForEach(this.videoArray.map((item, index) => {
    
    
          return {
    
     i: index, data: item };
        }),
          item => {
    
    
          //初始化@Link修饰的变量时需要用$修饰。
            PlayView({
    
     index: $index, pageShow: $pageShow, item: item.data, position: item.i })
          },
          item => item.data.id.toString())
      }
      .indicator(false) // 默认开启指示点
      .loop(false) // 默认开启循环播放
      .vertical(true) // 默认横向切换、更改为竖向滑动
      .onChange((index: number) => {
    
    //滚动Swiper的时候用来监听页面的变化
        //此处会触发PlayView的needPageShow方法。
        this.index = index
      })
    }
  }

2.4. Pause and play the video when the visible state of the page changes

When we press the home button, the APP enters the background. That is, when the state of the front and back of the APP changes, it needs to be notified PlayViewto pause or play. Implemented onPageShowand in PlayVideo, the value onPageHidechanged in these two methods , when the value of the value changes, because the function will monitor the change of the value, and the executed method is used to control the pause and playback of the video.pageShowpageShowPlayView@LinkPlayViewneedPageShow

 // 当此页面可见时触发,仅@Entry修饰的自定义组件生效
  onPageShow(): void  {
    
    
    //当pageShow的值发生改变时,PlayView因为@Link的作用会监听到值的改变,从而
    this.pageShow = true;
  }

  // 当此页面不可见时触发,仅@Entry修饰的自定义组件生效
  onPageHide(): void  {
    
    
    this.pageShow = false;
  }

2.5 PlayView and PageVidew source code:

All the source codes of the two are as follows. Of course, readers can download the entire project through Swiper to analyze and learn.


import {
    
    VideoItem} from '../play/VideoItem'

@Component
export struct PlayView {
    
    
  // 四条控制页面可见、页面不可见的控制
  private isShow: boolean = false // 是否是可见状态
  @Link @Watch("needPageShow") index: number // 监听父组件索引index状态变化, 不能在组件内部进行初始化
  @Link @Watch("needPageShow") pageShow: boolean // 监听父组件是否可见pageShow状态变化, 不能在组件内部进行初始化
  private position: number // 当前页面所在位置

  @ObjectLink private item: VideoItem // @Observed与@ObjectLink配合使用实现 class修饰的模型数据改变触发UI更新
  @State private playState: number = 0 // 0表示停止播放--stop   1表示开始播放--start   2表示暂停播放--pause

  // @ts-ignore
  private videoController: VideoController = new VideoController() // 视频播放器控制器

  build() {
    
    
    Stack({
    
     alignContent: Alignment.Center | Alignment.End }) {
    
    
      Video({
    
    
        src: this.item.src, // 视频播放地址
        controller: this.videoController // 视频播放器控制器
      })
        .controls(false) // 不需要控制栏
        .autoPlay(this.playState == 1 ? true : false) // 首次可见状态自动播放
        .objectFit(ImageFit.Contain) // 视频窗口自适应视频大小
        .loop(true) // 循环播放
        .onClick(() => {
    
     // 点击播放、再点击暂停播放
          if (this.playState == 1) {
    
    
            this.playState = 2;
            this.videoController.pause();
          } else if (this.playState == 2) {
    
    
            this.playState = 1;
            this.videoController.start();
          }
        })

      Column() {
    
    
        Image(this.item.isLikes ? $r('app.media.vote1') : $r('app.media.vote0')) // 点赞图标
          .width(36).height(36)
          .onClick(() => {
    
    
            if (this.item.isLikes) {
    
    
              this.item.likesCount--;
            } else {
    
    
              this.item.likesCount++;
            }
            this.item.isLikes = !this.item.isLikes;
          }).margin({
    
     top: 40 })
        Text(this.item.likesCount == 0 ? '点赞' : ('' + this.item.likesCount)).fontSize(16).fontColor(0xffffff) // 评论图标

        Image($r('app.media.comment'))
          .width(36).height(36).margin({
    
     top: 20 })
        Text(this.item.commentCount == 0 ? '评论' : ('' + this.item.commentCount))
          .fontSize(16)
          .fontColor(0xffffff) // 转发图标

        Image($r('app.media.share'))
          .width(36).height(36).margin({
    
     top: 20 })
      }.offset({
    
     x: '-5%', y: '-10%' }) // 位置调整

      Text(this.item.title)
        .fontSize(16)
        .fontColor(0xffffff)
        .margin(10)
        .offset({
    
     x: '-50%', y: '40%' })
    }.backgroundColor(Color.Black)
    .width('100%')
    .height('100%')
  }

  // 自定义的方法。页面可见状态会被调用,多次调用
  onPageShow(): void  {
    
    
    console.log("pageView*** OnPageShow")
    if (this.playState != 1) {
    
    
      this.playState = 1;
      this.videoController.start();
    }
  }

  // 自定义的方法。页面不可见状态会被调用,多次调用,这种不可见是Swiper滑动时触发的
  private onPageSwiperHide(): void  {
    
    
    console.log("playView*** onPageSwiperHide")
    if (this.playState != 0) {
    
    
      this.playState = 0;
      this.videoController.stop(); // 停止视频播放
    }
  }

  // 自定义的方法。页面不可见状态会被调用,多次调用,这种不可见是点击页面跳转、或者应用回到桌面时触发的
  onPageHide(): void  {
    
    
    console.log("playView*** onPageHide")
    if (this.playState != 2) {
    
    
      this.playState = 2;
      this.videoController.pause(); // 暂停视频播放
    }
  }

  // 监听父组件index、pageShow属性变化就会触发的方法,@Watch
  needPageShow() {
    
    
    console.log("playView*** needPageShow")
    if (this.pageShow) {
    
     // 页面可见时触发
      if (this.position == this.index) {
    
     // 判断index与当前所在位置是否相同
        this.isShow = true;
        this.onPageShow()
      } else {
    
    
        if (this.isShow) {
    
     // 已经是可见的状态改为不可见,并触发不可见方法回调
          this.isShow = false;
          this.onPageSwiperHide()
        }
      }
    } else {
    
     // 页面不可见触发
      if (this.position == this.index) {
    
    
        if (this.isShow) {
    
     // 已经是可见的状态改为不可见,并触发不可见方法回调
          this.isShow = false;
          this.onPageHide()
        }
      }
    }
  }
}


import {
    
     VideoItem, initializeOnStartup } from '../play/VideoItem'
import {
    
     PlayView } from '../play/PlayView'

@Entry
@Component
export struct PageVideo {
    
    
  @State videoArray: Array<VideoItem> = initializeOnStartup() // 数据源

  //当切换视频的时候,会通知PlayView播放当前的视频,同时关闭上一个视频
  @State index: number = 0 // 当前滑动的索引位置
  @State pageShow: boolean = false // 当前页面是否可见,仅对@Entry修饰的主页面PageVideo而言,子组件需要用@Watch监听该状态

  build() {
    
    
    Column() {
    
    
      Swiper() {
    
    
        ForEach(this.videoArray.map((item, index) => {
    
    
          return {
    
     i: index, data: item };
        }),
          item => {
    
    
            PlayView({
    
     index: $index, pageShow: $pageShow, item: item.data, position: item.i })
          },
          item => item.data.id.toString())
      }
      .indicator(false) // 默认开启指示点
      .loop(false) // 默认开启循环播放
      .vertical(true) // 默认横向切换、更改为竖向滑动
      .onChange((index: number) => {
    
    
        this.index = index
      })
    }
  }

  // 当此页面可见时触发,仅@Entry修饰的自定义组件生效
  onPageShow(): void  {
    
    
    this.pageShow = true;
  }

  // 当此页面不可见时触发,仅@Entry修饰的自定义组件生效
  onPageHide(): void  {
    
    
    this.pageShow = false;
  }
}

References:

HarmonyOS practical project list , share knowledge and insights, and explore the unique charm of HarmonyOS together. https://gitee.com/harmonyos/codelabs

HarmonyOS Hongmeng Study Notes (12) The role of @Link HarmonyOS Hongmeng Study Notes (8) Swiper realizes the effect
of carousel scrolling


Guess you like

Origin blog.csdn.net/chunqiuwei/article/details/127784581