HarmonyOS鸿蒙学习笔记(15)Swiper实现抖音切换视频播放效果

Posted 郭梧悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HarmonyOS鸿蒙学习笔记(15)Swiper实现抖音切换视频播放效果相关的知识,希望对你有一定的参考价值。

Swiper实战

1、项目结构

前面写了Swiper控件的初步使用,本文结合@Link@State@Watch来实现类似抖音滑动播放视频的效果。本文源码地址Swiper实战
项目结构如下图:

其中PageVideo.ets是APP首页,用来提供视频播放的列表。PlayView.ets是视频播放器,随着PageVideo.ets的滚动切换视频,来通知PlayView.ets暂停和开始视频的播放。VideoItem.ets包含着视频信息,比如视频播放地址等。

2、PageVideo和PlayView简单说明

2.1 @State变量的使用

PageVideo提供了两个@State修饰的变量:pageShownumber,这两个状态发生改变的时候会通知PlayView对播放器进行调整。

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

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

2.2 @Link和@Watch变量的使用

那么PlayView是如何感知这两个状态发生了改变了呢?此时@Link标签就起到了作用.PlayView代码如下:

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

其中也是用了@Watch标签定义了needPageShow的方法,当number和pageShow的值发生变化的时候会调用该方法,用来控制视频暂停上一个和播放当前的视频:


  // 监听父组件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、Swiper的使用和PlayView的初始化

在PlayVideo中根据视频的个数初始化了Swiper控件,该控件的子控件就是PlayView,注意在初始化PlayView时,初始化@Link修饰的变量时需要用$修饰。

 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、页面可见状态发生改变时对视频进行暂停和播放

我们按home键的时候,APP进入后台。也就是在APP前后台状态发生改变的时候,需要通知PlayView进行暂停或者播放。在PlayVideo里面实现了onPageShowonPageHide,在这两个方法里面改变pageShow的值,当pageShow的值发生改变时,PlayView因为@Link的作用会监听到值的改变,从而执行PlayViewneedPageShow方法用来控制视频的暂停和播放。

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

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

2.5 PlayView和PageVidew源码:

二者全部的源码如下,当然读者可以通过Swiper实战下载整个项目来分析和学习。


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;
  


参考资料:

鸿蒙实战项目表,分享知识与见解,一起探索HarmonyOS的独特魅力。https://gitee.com/harmonyos/codelabs

HarmonyOS鸿蒙学习笔记(12)@Link的作用
HarmonyOS鸿蒙学习笔记(8)Swiper实现轮播滚动效果
HarmonyOS鸿蒙学习笔记(5)@State作用说明和简单案例
Swiper实战
@Watch标签的作用

以上是关于HarmonyOS鸿蒙学习笔记(15)Swiper实现抖音切换视频播放效果的主要内容,如果未能解决你的问题,请参考以下文章

HarmonyOS鸿蒙学习笔记(15)Swiper实现抖音切换视频播放效果

HarmonyOS鸿蒙学习笔记Swiper实现轮播滚动效果

HarmonyOS鸿蒙学习笔记Swiper实现轮播滚动效果

HarmonyOS鸿蒙学习笔记Swiper实现轮播滚动效果

HarmonyOS鸿蒙学习笔记(14)@ObjectLink的作用

HarmonyOS鸿蒙学习笔记(14)@ObjectLink的作用