鸿蒙应用框架开发【媒体库视频】 UI框架

媒体库视频

介绍

本示例使用Video组件展示了视频组件的基本功能,包括视频组件化,全屏化,窗口化,上下轮播视频等。

效果预览

1

使用说明:

  1. 进入首页点击播放按键;
  2. 点击视频播放按钮,视频开始播放,再次点击视频进入视频全屏页;
  3. 首页下滑500vp后,视频小窗口化;
  4. 点击直播按钮进入直播页,上下滑动视频。

具体实现

  • 视频播放:start方法视频开始播放,源码参考[VideoPage.ets];
/*
 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { router } from '@kit.ArkUI';

@Component
export struct VideoPage {
  @State videoSrc: Resource = $rawfile('video1.mp4');
  @State controls: boolean = false;
  @State isFull: boolean = false;
  @State isPause: boolean = true;
  @State isPlayClick: boolean = true;
  @State firstClick: boolean = true;
  @State isHidden: boolean = true;
  @Link isStart: boolean;
  @Consume('playTime') updateTime: number;
  detailVideoController: VideoController = new VideoController();

  build() {
    Column() {
      Stack() {
        Video({
          src: this.videoSrc,
          controller: this.detailVideoController
        })
          .width('100%')
          .backgroundColor(this.isHidden ? '#ffffff' : '#000000')
          .aspectRatio(1.12)
          .controls(this.controls)
          .objectFit(ImageFit.Contain)
          .onUpdate((e) => {
            this.updateTime = e.time;
          })
          .onPrepared((e) => {
            console.info('VideoPage_onPrepared:' + e.duration);
          })
          .onClick(() => {
            // Check whether the play button has been used. If not, go to this layer.
            if (this.isPlayClick) {
              // Click the video for the first time to start playing.
              // Click the video again to enter the full screen.
              if (this.firstClick) {
                this.detailVideoController.start();
                this.isHidden = !this.isHidden;
                this.isStart = true;
                this.firstClick = !this.firstClick;
              } else {
                router.pushUrl({ url: 'pages/FullPage',
                  params: { videoSrc: this.videoSrc, videoTime: this.updateTime } });
              }
            } else {
              router.pushUrl({ url: 'pages/FullPage',
                params: { videoSrc: this.videoSrc, videoTime: this.updateTime } });
            }
          })
          .onFinish(() => {
            this.isHidden = true;
            this.isStart = false;
          })

        // Blank layer preview.
        if(this.isHidden){
          Column() {
            Image($r('app.media.previewImg'))
              .id('previewImg')
              .objectFit(ImageFit.Contain)
          }
          .width('100%')
          .aspectRatio(1.12)
          .backgroundColor('#ffffff')
        }

        if(this.isHidden){
          Column() {
            Image($r('app.media.play'))
              .id('playBtn')
              .width(76)
              .height(76)
              .onClick(() => {
                this.detailVideoController.start();
                this.isHidden = !this.isHidden;
                this.isStart = true;
                this.isPlayClick = false;
              })
          }
        }
      }
      .width('100%')
      .height('100%')
    }
  }
}
  • 全屏播放:再次点击视频进入全屏播放页面,使用setCurrentTime参数设定当前播放时间,pause方法停止播放,源码参考[FullPage.ets];
/*
 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { router } from '@kit.ArkUI';
import { mediaquery } from '@kit.ArkUI';
import { Callback } from '@kit.BasicServicesKit';

@Entry
@Component
export struct FullPage {
  @State fullParams: routerParams | null = null;
  @State fullSrc: Resource = $rawfile('video1.mp4');
  @State isHidden: boolean = false;
  @State maxValue: number = 0; // Total duration of the bottom time bar.
  @State nowValue: number = 0; // Current seconds of the bottom time bar.
  @State playTime: number = 0; // Playback time transferred from the previous page.
  @State isPhone: boolean = false;
  portraitFunc: Callback<mediaquery.MediaQueryResult> = (mediaQueryResult: mediaquery.MediaQueryResult): void => {
    this.onPortrait(mediaQueryResult);
  };
  listenerIsPhone = mediaquery.matchMediaSync('(orientation:landscape)');
  fullVideoController: VideoController = new VideoController();

  onPortrait(mediaQueryResult: mediaquery.MediaQueryResult) {
    this.isPhone = !mediaQueryResult.matches;
  }

  aboutToAppear() {
    this.fullParams = router.getParams() as routerParams;
    this.fullSrc = this.fullParams.videoSrc;
    this.playTime = this.fullParams.videoTime;
    this.listenerIsPhone.on('change', this.portraitFunc);
  }

  changTime(times: number): string {
    if (times <= 0) {
      return '00:00';
    } else {
      let mm = Math.floor(times / 60);
      let ss = Math.floor(times % 60);
      return (mm < 10 ? '0' + mm : mm) + ':' + (ss < 10 ? '0' + ss : ss);
    }
  }

  build() {
    Scroll() {
      Column() {
        Stack() {
          Video({
            src: this.fullSrc,
            controller: this.fullVideoController
          })
            .width('100%')
            .height('100%')
            .autoPlay(true)
            .loop(true)
            .controls(false)
            .objectFit(ImageFit.Contain)
            .id('fullVideo')
            .onPause(() => {
              this.isHidden = true;
            })
            .onFullscreenChange((e) => {
              this.isHidden = false;
            })
            .onStart(() => {
              this.isHidden = false;
            })
            .onPrepared((e) => {
              this.fullVideoController.setCurrentTime(this.playTime);
              this.maxValue = e.duration;
            })
            .onUpdate((e) => {
              this.nowValue = e.time;
            })
            .onClick(() => {
              this.fullVideoController.pause();
            })

          if(this.isHidden){
            Column() {
              Image($r('app.media.play'))
                .id('fullPlayBtn')
                .width(78)
                .height(78)
                .onClick(() => {
                  this.fullVideoController.start();
                  this.isHidden = !this.isHidden;
                })
            }
            .position({ x: this.isPhone ? '42%' : '47%', y: '45%' })
          }
        }
        .width('100%')
        .height('100%')

        Column() {
          Image($r('app.media.back'))
            .id('backBtn')
            .width(42)
            .height(42)
            .onClick(() => {
              router.back();
            })
        }
        .position({ x: '5%', y: '5%' })

        Column() {
          Image($r('app.media.share'))
            .width(42)
            .height(42)
        }
        .position({ x: this.isPhone ? '86%' : '95%', y: '5%' })

        // Bottom Time Bar.
        Row() {
          Text(this.changTime(Number.parseInt(this.nowValue.toFixed(0)))).fontSize(18).fontColor(Color.White)
          Slider({
            value: this.nowValue,
            min: 0,
            max: this.maxValue,
            style: SliderStyle.OutSet
          })
            .width('75%')
            .blockColor(Color.White)
            .trackColor('#cccccc')
            .selectedColor('#E92F4F')
            .showSteps(false)
            .onChange((value: number, mode: SliderChangeMode) => {
              this.nowValue = value;
              this.fullVideoController.setCurrentTime(value);
              console.info('value:' + value + 'mode:' + mode.toString());
            })
          Text(this.changTime(Number.parseInt(this.maxValue.toFixed(0))))
            .fontSize(18)
            .fontColor(Color.White)
        }
        .padding({ top: 50 })
        .width('100%')
        .position({ x: this.isPhone ? '3%' : '10%', y: '88%' })
      }
      .width('100%')
      .height('100%')
      .backgroundColor('#000000')
    }
  }
}

interface routerParams {
  videoSrc: Resource;
  videoTime: number;
}
  • 小窗口播放:记录当前播放时间,小窗口页面渲染之前设置视频当前播放时间,页面滚动到固定距离开始展示组件;
  • 直播:使用http接口的request方法获取直播数据,代码参考[Utils.ets];
/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { http } from '@kit.NetworkKit';

let httpRequest = http.createHttp();

export function Live() {
  return httpRequest.request(
    "http://123.60.114.86:8090/goods/liveInfo?id=2",
    {
      header: {
        'Content-Type': 'application/json'
      },
      readTimeout: 60000,
      connectTimeout: 60000
    });
}

以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
1

除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下

内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

鸿蒙【北向应用开发+南向系统层开发】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经

在这里插入图片描述

为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值