鸿蒙5.0&next开发【视频播放开发】媒体开发

概述

本文适用于视频播放类应用的开发,针对市场上主流视频播放类应用的常见场景,介绍了如何基于HarmonyOS能力快速实现视频播放应用。

从用户交互和音频流状态变更两个维度,指导开发者基于HarmonyOS提供的媒体和ArkUI等能力,实现视频前后台播放控制、播放形态切换、音频焦点切换、播放设备切换等场景,可以为视频播放应用提供灵活的交互体验和良好的观看效果。

场景分析

场景名称 子场景名称 描述 实现方案
与用户交互 [播放进度控制] 进度条控制。 使用[Slider组件]实现进度条,在其onChange回调中触发进度调节。
手势调节播放进度。 通过给组件[绑定手势识别],来实现手势调节播放进度。
显示进度条弹窗。 给进度条添加[Popup弹窗]。
[播放形态切换] 横竖屏切换。 基于[窗口能力]实现全屏播放。
悬浮窗播放。 [应用布局适配智慧多窗]。
[播控中心控制视频状态] 应用响应播控中心通知,向播控中心同步视频信息状态。 [监听AVSession播放状态事件]。
[视频后台播放] 应用至于后台时可以继续播放。 基于[AVSession Kit]和[Background Tasks Kit]申请长时任务。
[滑动调节音量及亮度] 视频全屏播放时,可以滑动屏幕调节音量及亮度。 使用[AVVolumePanel组件]控制音量,使用[Slider组件]及[setWindowBrightness]方法控制亮度。
音频流状态变更 [多音频并发打断] 视频应用被其他应用的音频打断做出对应的行为。 [AVPlayer监听音频打断事件]。
[播放设备切换] 视频应用连接的播放设备状态发生变更时做出对应的行为。 [AVPlayer监听设备音频流输出变化]。

与用户交互

播放进度控制

进度条控制

进度条作为视频应用的一个基础能力,可以通过点击或拖动进度条来调节视频播放进度。采用[Slider组件]实现进度条功能,根据Slider组件属性设置进度条样式,并在其onChange()事件中触发视频播放器AVPlayer的seek()方法,实现视频进度的控制。

Slider({
  value: this.isSliderGesture ? this.panEndTime : this.avPlayerController.currentTime,
  step: 0.1,
  min: 0,
  max: this.avPlayerController.durationTime,
  style: this.sliderStyle
})
  // ...
  .trackColor($r('app.color.white_opacity_1_color')) // 滑轨背景颜色
  .showSteps(false) // 是否显示步长刻度
  .blockSize({ width: this.blockSize, height: this.blockSize }) // 滑块大小
  .blockColor($r('sys.color.background_primary')) // 滑块颜色
  .trackThickness(this.trackThicknessSize) // 滑轨粗细
  .trackBorderRadius(2) // 底板圆角半径
  .selectedBorderRadius(2) // 已滑动部分圆角半径
  // ...
  .onChange((value: number, mode: SliderChangeMode) => {
    this.sliderOnchange(value, mode); // 进度条变化接口
  })

sliderOnchange(seconds: number, mode: SliderChangeMode) {
  let seekTime: number = seconds * this.avPlayerController.duration / this.avPlayerController.durationTime;
  this.currentStringTime = secondToTime(Math.floor(seekTime / 1000));
  this.avPlayerController.setCurrentStringTime(this.currentStringTime);
  switch (mode) {
    case SliderChangeMode.Begin:
      break;
    case SliderChangeMode.Click:
      break;
    case SliderChangeMode.Moving:
      // ...
      break;
    case SliderChangeMode.End:
      this.avPlayerController.seek(seekTime); // 调用AVPlayer的seek方法控制播放进度
      // ...
      break;
    default:
      break;
  }
}

手势调节播放进度

通常视频播放应用还可以支持手势滑动来调节播放的进度,可以给组件绑定手势识别,来实现在视频界面左右滑动调节视频播放进度的能力,手势类型选择[PanGesture](平移手势)。

  1. onActionStart()阶段使用本地变量记录当前视频播放的位置,并更新进度条状态变量,重新渲染UI界面;
  2. onActionUpdate()阶段根据滑动的距离,计算滑动后视频应跳转的播放位置,并渲染UI界面进度条动效;
  3. onActionEnd()阶段将最终计算出的播放位置传给AVPlayer控制器,调用AVPlayer的seek()方法让视频跳转到指定播放位置,并更新进度条状态变量,重新渲染UI界面。
build() {
  Stack({ alignContent: Alignment.BottomEnd }) {
    // ...
    XComponent({
      id: 'XComponent',
      type: XComponentType.SURFACE,
      controller: this.xComponentController
    })
    // ...
  }
   // ...
  .gesture(
    PanGesture({ direction: PanDirection.Horizontal })
      .onActionStart((event: GestureEvent) => {
        this.isSliderGesture = true;
        this.panStartX = event.offsetX;
        this.panStartTime = this.avPlayerController.currentTime;
        this.sliderOnchange(this.panStartTime, SliderChangeMode.Begin);
      })
      .onActionUpdate((event: GestureEvent) => {
        this.isSliderGesture = true;
        let panTime =
          this.panStartTime +
            (this.panStartX + event.offsetX) / this.slideWidth * this.avPlayerController.durationTime;
        this.panEndTime = Math.min(Math.max(0, panTime), this.avPlayerController.durationTime);
        this.sliderOnchange(this.panEndTime, SliderChangeMode.Moving);
      })
      .onActionEnd(() => {
        this.sliderOnchange(this.panEndTime, SliderChangeMode.End);
        this.isSliderGesture = false;
      })
  )
}

显示进度条弹窗

在正常浏览视频的过程中,应用会记录用户的浏览历史,当再次切换到原视频时,根据历史数据在进度条上以弹窗的形式显示相关信息。并且让弹窗跟随滑块位置移动,弹窗保留1秒后消失。同时历史数据的保留跟随视频组件的生命周期存亡。

由于Slider自带的showTips无法对弹窗样式进行自定义,只支持圆形气泡,且无法自定义控制弹窗的显示时长和出现时机。所以我们通过创建一个和Slider滑块大小一致的透明Stack,并计算滑块在屏幕中的位置,将计算的位置数据同步设置给Stack,并给Stack绑定Popup弹窗跟随Slider滑块运动。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

关键代码:

通过给Slider组件绑定区域变化事件onAreaChange(),计算滑动位置信息。

// Slider进度条
Slider({
  value: this.isSliderGesture ? this.panEndTime : this.avPlayerController.currentTime,
  step: 0.1,
  min: 0,
  max: this.avPlayerController.durationTime,
  style: this.sliderStyle
})
  // ...
  .blockSize({ width: this.blockSize, height: this.blockSize })
  // 计算滑块位置
  .onAreaChange(() => {
    let videoSlider: componentUtils.ComponentInfo = componentUtils.getRectangleById('video_slider')
    this.slideWidth = px2vp(videoSlider.size.width);
    // 计算offsetY:Slider滑块位置的纵坐标
    this.offsetY = px2vp(videoSlider.localOffset.y);
    this.beginX = px2vp(videoSlider.localOffset.x);
  })
  // 进度条变化时最终会调用avPlayer.seek()接口
  .onChange((value: number, mode: SliderChangeMode) => {
    this.sliderOnchange(value, mode);// 进度条变化时会调用avPlayer.seek()接口
  })

Stack透明块大小、位置设置以及给Stack绑定Popup弹窗。

// 设置和Slider大小一样的透明stack块
Stack() {
}
.backgroundColor($r('sys.color.background_primary'))
.width(this.b
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值