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

news2024/11/16 16:30:23

媒体库视频

介绍

本示例使用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内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!

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

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

鸿蒙面经

在这里插入图片描述

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1972098.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CTFHub技能树web——XSS——DOM反射

根据框里的内容 直接右键查看网页源代码 看到 了其闭合方式 然后去网页测试一下alert&#xff08;1&#xff09;反射 ;</script><script>alert(1)</script> 看到 确实存在 去xssaq.cn 创建一个项目 把src粘过来 在第一个输入框中 再将返回回来的url 复…

NAND行业回归盈利:AI与云存储需求驱动

市场概览 根据Yole Group于2024年6月25日发布的市场报告&#xff0c;经过五个季度的亏损之后&#xff0c;NAND闪存行业在2024年第一季度&#xff08;1Q24&#xff09;实现了盈利回归。这一转变主要得益于企业级固态硬盘&#xff08;SSD&#xff09;领域的强劲需求增长&#xf…

【教程】Python语言的地球科学常见数据——海温数据-NOAA OISST 的处理

NOAA 1/4每日最佳内插海面温度&#xff08;OISST&#xff09;是一个长期的气候数据记录&#xff0c;它将来自 不同平台&#xff08;卫星、船舶、浮标和 Argo 浮标&#xff09;的观测数据纳入一个定期的全球网格。该 数据集经过插值处理&#xff0c;以填补网格上的空白&#x…

创意无限:11个设计圈热议的UI设计灵感网站集锦

无论你是一个经验丰富的UI设计师还是一个新的UI设计师&#xff0c;拥有一些高质量、可靠的UI设计网站灵感库都能加速你的设计过程。借助灵感资源&#xff0c;您可以更快、更有效地启动该项目。与此同时&#xff0c;优秀的UI设计网站也能帮助您探索新的设计解决方案&#xff0c;…

3DsMax展开管道UV,展开圆柱体UV,展开带有拐弯部分的UV

效果 3dsmax展开管道的UV 创建管道 创建样条线 制作弯曲部分 打开样条线先的顶点&#xff0c;选择样条线的顶点&#xff0c;不选中&#xff0c;开头和结尾的顶点&#xff0c;点击圆角 &#xff0c;鼠标移动到顶点上&#xff0c;左键点击顶点然后向上拖拽。 设置样条线可渲染…

隐私安全测试:保护您的数字世界

大家好&#xff0c;我是一名_全栈_测试开发工程师&#xff0c;已经开源一套【自动化测试框架】和【测试管理平台】&#xff0c;欢迎大家关注我&#xff0c;和我一起【分享测试知识&#xff0c;交流测试技术&#xff0c;趣聊行业热点】。 一、引言 在当今数字化的时代&#xff0…

安装Docker以及安装过程中的错误解决

一、纯享版教程&#xff0b;操作截图 环境&#xff1a;centOs 7 FinalShell &#xff01;&#xff01;&#xff01;此教程针对第一次安装docker的友友&#xff0c;如果已经安装过且报错的朋友&#xff0c;请移步报错合集。 1.卸载旧版本&#xff08;无论是否安装过都建议执…

C++11深度剖析

目录 &#x1f680; 前言&#xff1a;C11简介 一&#xff1a; &#x1f525; 统一的列表初始化&#x1f4ab; 2.1 &#xff5b;&#xff5d;初始化 二&#xff1a; &#x1f525; std::initializer_list &#x1f4ab; 2.1 std::initializer_list是什么类型&#x1f4ab; 2.2 s…

【LLM】-14-搭建问答系统

核心流程说明&#xff1a; 对用户的输入进行检验&#xff0c;验证其是否可以通过审核 API 的标准。若输入顺利通过审核&#xff0c;我们将进一步对产品目录进行搜索。若产品搜索成功&#xff0c;我们将继续寻找相关的产品信息。我们使用模型针对用户的问题进行回答。最后&…

C++ : namespace,输入与输出,函数重载,缺省参数

一&#xff0c;命名空间(namespace) 1.1命名空间的作用与定义 我们在学习c的过程中&#xff0c;经常会碰到命名冲突的情况。就拿我们在c语言中的一个string函数来说吧&#xff1a; int strncat 0; int main() {printf("%d", strncat);return 0; } 当我们运行之后&…

内网横向——常见系统传递攻击(1)

文章目录 一、哈希传递1.1 利用Mimikatz进行PTH1.2 利用Impacket进行PTH1.3 使用crackmapexec进行PTH1.4 使用PowerShell1.5 使用MSF进行哈希传递1.6 利用哈希传递登录远程桌面 二、票据传递2.1 MS14-068漏洞2.2 使用kekeo进行票据传递 网络拓扑&#xff1a; 攻击机kali IP&…

windows内存泄漏检查汇总

VLD(Visual Leak Detector) 下载 官方下载地址2.5 另一分支2.7 安装 点击运行安装

重装系统之前,如何保护自己的微信聊天记录?

前言 有个小伙伴想要重装系统&#xff0c;但又怕自己的电脑微信聊天记录全没了。于是就一直拖着不重装系统&#xff0c;直到有一天系统崩溃之后…… 今天咱们要讲讲&#xff1a;重装系统之前&#xff0c;如何保护自己的社交软件聊天记录。这个话题其实不仅仅是微信聊天记录&am…

喜讯|华院计算Uni-law法律大模型成功入选《2024中国数据智能产业AI大模型先锋企业》

7月24日&#xff0c;“2024企业数智化转型升级发展论坛——暨AI大模型趋势论坛”在北京圆满落幕。此次论坛由数据猿主办&#xff0c;IDC协办&#xff0c;新华社中国经济信息社、上海大数据联盟、上海市数商协会及上海超级计算中心作为支持单位。大会以“数智新质力拓未来”为主…

Springboot学习-day17

Springboot学习-day17 1. AOP AOP &#xff08;Aspect Orient Programming&#xff09;,直译过来就是 面向切面编程,AOP 是一种编程思想&#xff0c;是面向对象编程&#xff08;OOP&#xff09;的一种补充。 面向切面编程&#xff0c;实现在不修改源代码的情况下给程序动态统…

大模型学习路线图:从入门到精通,我说这是全网详细的,谁赞成谁反对?

随着人工智能技术的飞速发展&#xff0c;大模型&#xff08;Large-Scale Models&#xff09;已经成为推动自然语言处理&#xff08;NLP&#xff09;、计算机视觉&#xff08;CV&#xff09;等领域进步的关键因素。本文将为您详细介绍从零开始学习大模型直至成为专家的全过程&am…

吴恩达机器学习WEEK1

COURSE 1 WEEK 1 机器学习的应用 当我们有一个目标&#xff0c;不知道如何显示地写出来一个程序时&#xff0c;例如自动驾驶等&#xff0c;这时候就需要制定某些规则&#xff0c;让计算机自己去学习&#xff0c;即机器学习 机器学习就是沿用人脑学习的过程&#xff0c;逐步对…

目录文件;链接文件;函数stat/lstat

1.目录文件的操作&#xff1a; 1. mkdir int mkdir(const char *pathname, mode_t mode); 功能: 创建目录 参数&#xff1a; pathname:目录文件的路径 mode:目录文件的权限 返回值&#xff1a; …

6581 Number Triangle

这个问题可以通过动态规划来解决。我们可以从三角形的顶部开始&#xff0c;然后逐行向下计算每个位置的最大和。对于三角形中的每个位置&#xff0c;我们可以选择从其上方或左上方的位置移动到该位置&#xff0c;所以该位置的最大和就是其上方或左上方位置的最大和加上该位置的…

动态规划---观察优化枚举(股票系列问题)

121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; public class Code01_Stock1 {public static int maxProfit(int[] prices) {int ans 0;for (int i 1, min prices[0]; i < prices.length; i) {// min : 0...i范围上的最小值min Math.min(min, prices…