• HarmonyOS ArkTS Video组件的使用(七)


    概述

    在手机、平板或是智慧屏这些终端设备上,媒体功能可以算作是我们最常用的场景之一。无论是实现音频的播放、录制、采集,还是视频的播放、切换、循环,亦或是相机的预览、拍照等功能,媒体组件都是必不可少的。以视频功能为例,在应用开发过程中,我们需要通过ArkUI提供的Video组件为应用增加基础的视频播放功能。借助Video组件,我们可以实现视频的播放功能并控制其播放状态。常见的视频播放场景包括观看网络上的较为流行的短视频,也包括查看我们存储在本地的视频内容。

    Video组件用法介绍

    Video组件参数介绍

    Video组件的接口表达形式为:

    Video(value: {src?: string | Resource, currentProgressRate?: number | string |PlaybackSpeed, previewUri?: string |PixelMap | Resource, controller?: VideoController})
    
    • 1

    其中包含四个可选参数,src、currentProgressRate、previewUri和controller。

    • src表示视频播放源的路径,可以支持本地视频路径和网络路径。使用网络地址时,如https,需要注意的是需要在module.json5文件中申请网络权限。在使用本地资源播放时,当使用本地视频地址我们可以使用媒体库管理模块medialibrary来查询公共媒体库中的视频文件,示例代码如下:
    import mediaLibrary from '@ohos.multimedia.mediaLibrary';
    
    async queryMediaVideo() {
      let option = {
        // 根据媒体类型检索
        selections: mediaLibrary.FileKey.MEDIA_TYPE + '=?',
        // 媒体类型为视频
        selectionArgs: [mediaLibrary.MediaType.VIDEO.toString()]
      };
      let media = mediaLibrary.getMediaLibrary(getContext(this));
      // 获取资源文件
      const fetchFileResult = await media.getFileAssets(option);
      // 以获取的第一个文件为例获取视频地址
      let fileAsset = await fetchFileResult.getFirstObject();
      this.source = fileAsset.uri
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    为了方便功能演示,示例中媒体资源需存放在resources下的rawfile文件夹里。

    • currentProgressRate表示视频播放倍速,其参数类型为number,取值支持0.75,1.0,1.25,1.75,2.0,默认值为1.0倍速;
    • previewUri表示视频未播放时的预览图片路径;
    • controller表示视频控制器。

    参数的具体描述如下表:

    在这里插入图片描述
    下面我们通过具体的例子来说明参数的使用方法,我们选择播放本地视频,视频未播放时的预览图片路径也为本地,代码实现如下:

    @Component
    export struct VideoPlayer {
      private source: string | Resource;
      private controller: VideoController;
      private previewUris: Resource = $r('app.media.preview');
      ...
    
      build() {
        Column() {
          Video({
            src: this.source,
            previewUri: this.previewUris,
            controller: this.controller
          })
            ...
          VideoSlider({ controller: this.controller })
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    效果如下:

    在这里插入图片描述

    Video组件属性介绍

    除了支持组件的尺寸设置、位置设置等通用属性外,Video组件还支持是否静音、是否自动播放、控制栏是否显示、视频显示模式以及单个视频是否循环播放五个私有属性。

    在这里插入图片描述

    其中,objectFit 中视频显示模式包括Contain、Cover、Auto、Fill、ScaleDown、None 6种模式,默认情况下使用ImageFit.Cover(保持宽高比进行缩小或者放大,使得图片两边都大于或等于显示边界),其他效果(如自适应显示、保持原有尺寸显示、不保持宽高比进行缩放等)可以根据具体使用场景/设备来进行选择。

    在Codelab示例中体现了controls、autoplay和loop属性的配置,示例代码如下:

    @Component
    export struct VideoPlayer {
      private source: string | Resource;
      private controller: VideoController;
      ...
      build() {
        Column() {
          Video({
            controller: this.controller
          })
            .controls(false) //不显示控制栏 
            .autoPlay(false) // 手动点击播放 
            .loop(false) // 关闭循环播放 
            ...
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Video组件回调事件介绍

    Video组件能够支持常规的点击、触摸等通用事件,同时也支持onStart、onPause、onFinish、onError等事件,具体事件的功能描述见下表:

    在这里插入图片描述
    在Codelab中我们以更新事件、准备事件、失败事件以及点击事件为回调为例进行演示,代码实现如下:

    Video({ ... })
      .onUpdate((event) => {
        this.currentTime = event.time;
        this.currentStringTime = changeSliderTime(this.currentTime); //更新事件 
      })
      .onPrepared((event) => {
        prepared.call(this, event); //准备事件 
      })
      .onError(() => {
        prompt.showToast({
          duration: COMMON_NUM_DURATION, //播放失败事件 
          message: MESSAGE
        });
      ...
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    其中,onUpdate更新事件在播放进度变化时触发,从event中可以获取当前播放进度,从而更新进度条显示事件,比如视频播放时间从24秒更新到30秒。onError事件在视频播放失败时触发,在CommonConstants.ets中定义了常量类MESSAGE,所以在视频播放失败时会显示“请检查网络”。

    const MESSAGE: string = '请检查网络'  
    
    • 1

    自定义控制器的组成与实现

    自定义控制器的组成

    Video组件的原生控制器样式相对固定,当我们对页面的布局色调的一致性有所要求,或者在拖动进度条的同时需要显示其百分比进度时,原生控制器就无法满足需要了。如下图右侧的效果需要使用自定义控制器实现,接下来我们看一下自定义控制器的组成。

    在这里插入图片描述

    为了实现自定义控制器的进度显示等功能,我们需要通过Row容器实现控制器的整体布局,然后借由Text组件来显示视频的播放起始时间、进度时间以及视频总时长,最后通过滑动进度条Slider组件来实现视频进度条的效果,代码如下:

    @Component
    export struct VideoSlider {
      ...
      build() {
        Row(...) {
          Image(...)
          Text(...)
          Slider(...)
          Text(...)
        }
        ...
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    自定义控制器的实现

    自定义控制器容器内嵌套了视频播放时间Text组件、滑动器Slider组件以及视频总时长Text组件 3个横向排列的组件,其中Text组件在之前的基础组件课程中已经有过详细介绍,这里就不再进行赘述。需要强调的是两个Text组件显示的时长是由Slider组件的onChange(callback: (value: number, mode: SliderChangeMode) => void)回调事件来进行传递的,而Text组件的数值与视频播放进度数值value则是通过@Provide与 @Consume装饰器进行的数据联动,实现效果可见图片下方黑色控制栏部分,具体代码步骤及代码如下:

    获取/计算视频时长

    export function prepared(event) {
      this.durationTime = event.duration;
      let second: number = event.duration % COMMON_NUM_MINUTE;
      let min: number = parseInt((event.duration / COMMON_NUM_MINUTE).toString());
      let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min;
      let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second;
      this.durationStringTime = `${head}${SPLIT}${end}`;
      ...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    设置进度条参数及属性

    Slider({
      value: this.currentTime,
      min: 0,
      max: this.durationTime,
      step: 1,
      style: SliderStyle.OutSet
    })
      .blockColor($r('app.color.white'))
      .width(STRING_PERCENT.SLIDER_WITH)
      .trackColor(Color.Gray)
      .selectedColor($r('app.color.white'))
      .showSteps(true)
      .showTips(true)
      .trackThickness(this.isOpacity ? SMALL_TRACK_THICK_NESS : BIG_TRACK_THICK_NESS)
      .onChange((value: number, mode: SliderChangeMode) => {...})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    计算当前进度播放时间及添加onUpdate回调

    最后,在我们播放视频时还需要更新显示播放的时间进度,也就是左侧的Text组件。在视频开始播放前,播放时间默认为00:00,随着视频播放,时间需要不断更新为当前进度时间。所以左侧的Text组件我们不仅需要读取时间,还需要为其添加数据联动。这里,我们就是通过为Video组件添加onUpdate事件来实现的,在视频播放过程中会不断调用changeSliderTime方法获取当前的播放时间并进行计算及单位转化,从而不断刷新进度条的值,也就是控制器左侧的播放进度时间Text组件。

    Video({...})
      ...
      .onUpdate((event) => {
        this.currentTime = event.time;
        this.currentStringTime = changeSliderTime(this.currentTime)
      }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    export function changeSliderTime(value: number): string {
      let second: number = value % COMMON_NUM_MINUTE;
      let min: number = parseInt((value / COMMON_NUM_MINUTE).toString());
      let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min;
      let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second;
      let nowTime = `${head}${SPLIT}${end}`;
      return nowTime;
    }; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    指定视频播放进度及添加onChange事件回调

    如需手动进行进度条的拖动,则需要在Slider组件中指定播放进度,并为Slider组件添加onChange事件回调。Slider滑动时就会触发该事件回调,从而实现将视频定位到进度条当前刷新位置,完成时长组件渲染与视频播放进度数据联动。

    Slider({...})
      .onChange((value: number, mode: SliderChangeMode) => {
        sliderOnchange.call(this, value, mode);
      })
    
    • 1
    • 2
    • 3
    • 4
    export function sliderOnchange(value: number, mode: SliderChangeMode) {
      this.currentTime = parseInt(value.toString());
      this.controller.setCurrentTime(parseInt(value.toString()), SeekMode.Accurate);
      ...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    到这里我们就实现了自定义控制器的构建,两个Text组件显示的时长是由Slider组件的onChange回调事件来进行传递的,而Text组件的数值与视频播放进度数值value则通过是onUpdate与onChange事件并借由@Provide @Consume装饰器进行的数据联动。

  • 相关阅读:
    高斯混合模型GMM及EM迭代求解算法(含代码实现)
    swift-类结构源码探寻(一)
    排序算法-选择排序
    元宇宙崛起:区块链与金融科技共绘数字新世界
    第十五章 图的BFS与拓扑序列
    交叉编译嵌入式linux平台的gdb工具
    数智未来 持续创新 | 易趋受邀出席CIAS 2022中国数智汽车峰会
    python作图
    前序中序、中序后序以及前序后序构造二叉树
    Linux网络编程|TCP编程
  • 原文地址:https://blog.csdn.net/Chen_xiaobao/article/details/134545487