HarmonyOS鸿蒙Next中如何解决AVPlayer在List组件中无法实现全屏播放问题

HarmonyOS鸿蒙Next中如何解决AVPlayer在List组件中无法实现全屏播放问题

【问题现象】

在List组件中,AVPlayer播放器作为ListItem的子元素,视频播放无法全屏显示。

【背景知识】

  • AVPlayer:实现端到端播放原始媒体资源。
  • 窗口沉浸式能力:在看视频、玩游戏等场景下,隐藏状态栏、导航栏等不必要的系统窗口,从而获得更佳的沉浸式体验。
  • 窗口方向:设置主窗口的方向。

【定位思路】

  • AVPlayer只是把Surface画布绑定到AVPlayer上,不提供旋转、全屏接口,这些都要应用自己操作Surface全屏、旋转来实现,AVPlayer只是一个不带界面的播放器。所以实现全屏需要通过操作Surface实现全屏、旋转。
  • 在点击全屏按钮时,隐藏其它ListItem,仅显示选中项;点击横屏按钮时,设置窗口方向,并设置XComponent组件宽高铺满屏幕,实现全屏播放效果。

【解决方案】

1. 初始化视频列表数据源

代码示例如下:

private data: myVideoSourceData = new myVideoSourceData([]);
aboutToAppear(): void {
  let list: VideoSource[] = [
      new VideoSource("文案1", "IAP支付白屏.mp4"),
      new VideoSource("文案2", "IAP支付白屏.mp4"),
      new VideoSource("文案3", "video3.mp4"),
      new VideoSource("文案4", "video4.mp4")
  ];

  this.data = new myVideoSourceData(list);
}

2. List + LazyForEach组件渲染视频列表

代码示例如下:

build() {
  // 通过显隐控制控制其他listItem是否展示
  Column() {
    Text(this.item.text)
      .visibility(this.isLayoutFullScreen === false ? Visibility.Visible : Visibility.None)
    Stack() {
      XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.mXComponentController })
        .onLoad(() => {
          this.player = new AVPlayerDemo();
          this.player.setSurfaceID(this.mXComponentController.getXComponentSurfaceId());
        })
        .height(this.isLayoutFullScreen ? (this.isLandScape ? '100%' : 200) : "100%")
      // 视频按钮布局
      // ...
    }
    .backgroundColor(Color.Black)
    .height(this.isLayoutFullScreen ? "100%" : 200)
  }
  .onVisibleAreaChange([0.2, 1.0], async (isVisible: boolean, currentRatio: number) => {
    if (!isVisible && currentRatio < 0.2) {
      if (this.player && isPlaying.length !== 0 && this.player === isPlaying[0]) {
        console.info('onVisibleAreaChange')
        this.player.release();
        isPlaying[0].release();
        isPlaying.pop();
      }
    }
  })
  .width('100%')
}

3. 窗口方向(横屏)、窗口沉浸式设置

代码示例如下:

// 设置窗口方向
setR(orientation: number) {
  window.getLastWindow(getContext(this)).then((win) => {
    win.setPreferredOrientation(orientation).then((data) => {
      console.log('setWindowOrientation: ' + orientation + ' Succeeded. Data: ' + JSON.stringify(data));
    }).catch((err: string) => {
      console.log('setWindowOrientation: Failed. Cause: ' + JSON.stringify(err));
    });
  }).catch((err: string) => {
    console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err));
  });
}

// 设置沉浸式窗口
setFullScreen(isLayoutFullScreen: boolean) {
  window.getLastWindow(getContext(this)).then((win) => {
    win.setWindowLayoutFullScreen(isLayoutFullScreen, (err: BusinessError) => {
      const errCode: number = err.code;
      if (errCode) {
        console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
        return;
      }
      console.info('Succeeded in setting the window layout to full-screen mode.');
    });
  }).catch((err: string) => {
    console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err));
  });
}

4. 添加全屏、退出全屏、横屏等按钮

代码示例如下:

Button("点击全屏")
  .onClick(() => {
    this.fangDaIndex = this.index
    this.isLayoutFullScreen = true
    this.setFullScreen(this.isLayoutFullScreen)
  })
  .backgroundColor(this.bkColor)

Button("退出全屏")
  .onClick(() => {
    this.setR(1);
    this.isLayoutFullScreen = false;
    this.isLandScape = false;
    this.setFullScreen(this.isLayoutFullScreen)
  })
  .backgroundColor(this.bkColor)

Button("横屏")
  .onClick(() => {
    this.fangDaIndex = this.index;
    this.setR(4);
    this.isLandScape = true;
    this.isLayoutFullScreen = true;
    this.setFullScreen(this.isLayoutFullScreen)
  })
  .backgroundColor(this.bkColor)

解决问题后截图展示:

点击放大 点击放大 点击放大

【总结】

AVPlayer可以自定义全屏效果,当需要在List组件中实现AVPlayer全屏播放效果时,可以通过隐藏其它组件,设置窗口横屏、沉浸式,并且使XComponent组件铺满全屏,从而达到全屏播放的效果。

该方案,对于List+Video实现的视频列表同样有效。但是对于多层嵌套的场景,需要结合NodeContainer实现。


更多关于HarmonyOS鸿蒙Next中如何解决AVPlayer在List组件中无法实现全屏播放问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中如何解决AVPlayer在List组件中无法实现全屏播放问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,通过以下步骤解决AVPlayer在List组件中无法实现全屏播放问题:

  1. 初始化视频列表数据源:创建视频数据源并初始化。
  2. 使用List + LazyForEach组件渲染视频列表:通过显隐控制其他ListItem是否展示,使用XComponent绑定AVPlayer的Surface画布。
  3. 设置窗口方向和沉浸式窗口:通过setPreferredOrientation设置窗口方向为横屏,通过setWindowLayoutFullScreen设置沉浸式窗口。
  4. 添加全屏、退出全屏、横屏等按钮:通过按钮点击事件控制全屏、退出全屏和横屏操作,调整XComponent组件的宽高以铺满屏幕。

具体代码实现如下:

// 设置窗口方向
setR(orientation: number) {
  window.getLastWindow(getContext(this)).then((win) => {
    win.setPreferredOrientation(orientation).then((data) => {
      console.log('setWindowOrientation: ' + orientation + ' Succeeded. Data: ' + JSON.stringify(data));
    }).catch((err: string) => {
      console.log('setWindowOrientation: Failed. Cause: ' + JSON.stringify(err));
    });
  }).catch((err: string) => {
    console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err));
  });
}

// 设置沉浸式窗口
setFullScreen(isLayoutFullScreen: boolean) {
  window.getLastWindow(getContext(this)).then((win) => {
    win.setWindowLayoutFullScreen(isLayoutFullScreen, (err: BusinessError) => {
      const errCode: number = err.code;
      if (errCode) {
        console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
        return;
      }
      console.info('Succeeded in setting the window layout to full-screen mode.');
    });
  }).catch((err: string) => {
    console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err));
  });
}

// 添加全屏、退出全屏、横屏等按钮
Button("点击全屏")
  .onClick(() => {
    this.fangDaIndex = this.index
    this.isLayoutFullScreen = true
    this.setFullScreen(this.isLayoutFullScreen)
  })
  .backgroundColor(this.bkColor)

Button("退出全屏")
  .onClick(() => {
    this.setR(1);
    this.isLayoutFullScreen = false;
    this.isLandScape = false;
    this.setFullScreen(this.isLayoutFullScreen)
  })
  .backgroundColor(this.bkColor)

Button("横屏")
  .onClick(() => {
    this.fangDaIndex = this.index;
    this.setR(4);
    this.isLandScape = true;
    this.isLayoutFullScreen = true;
    this.setFullScreen(this.isLayoutFullScreen)
  })
  .backgroundColor(this.bkColor)

通过以上步骤,可以在List组件中实现AVPlayer的全屏播放效果。

回到顶部