鸿蒙4.0实战教学—基础ArkTS(简易视频播放器)

news2025/1/22 17:52:16

构建主界面

主界面由视频轮播模块和多个视频列表模块组成,效果图如图:

VideoData.ets中定义的视频轮播图数组SWIPER_VIDEOS和视频列表图片数组HORIZONTAL_VIDEOS。

// VideoData.ets
import { HorizontalVideoItem } from './HorizontalVideoItem';
import { SwiperVideoItem } from './SwiperVideoItem';

export const SWIPER_VIDEOS: SwiperVideoItem[] = [
  new SwiperVideoItem($r('app.media.banner1')),
  new SwiperVideoItem($r('app.media.banner2')),
  new SwiperVideoItem($r('app.media.banner3'))
];

export const HORIZONTAL_VIDEOS: HorizontalVideoItem[] = [
  new HorizontalVideoItem(1, $r('app.media.video_list0'), '视频1'),
  new HorizontalVideoItem(2, $r('app.media.video_list1'), '视频2'),
  new HorizontalVideoItem(3, $r('app.media.video_list2'), '视频3')
];

IndexSwiper.ets文件中定义的轮播图子组件SwiperVideo,点击轮播图片,页面跳转到视频播放页面,并携带本地视频flag,效果图如图:

// IndexSwiper.ets
@Component
export struct SwiperVideo {
  build() {
    Column() {
      Swiper() {
        ForEach(SWIPER_VIDEOS, (item: SwiperVideoItem) => {
          SwiperItem({ imageSrc: item.image, source: $rawfile('videoTest.mp4') })
        }, (item: SwiperVideoItem) => JSON.stringify(item))
      }
      .autoPlay(true)
    }
    // 样式设置
    ...
  }
}

@Component
struct SwiperItem {
  private imageSrc: Resource = $r('app.string.empty');
  private source: Resource = $r('app.string.empty');
  private paramItem: ParamItem = new ParamItem();
  ...

  build() {
    // 跳转一:使用Navigator组件跳转到视频播放界面
    Navigator({ target: SECOND_PAGE, type: NavigationType.Push }) {
      Image(this.imageSrc)
        .borderRadius(MARGIN_FONT_SIZE.FIRST_MARGIN)
    }
    .params(this.paramItem)
  }
}

IndexModule.ets文件中定义的视频列表图片子组件VideoModule,点击子组件中的图片,页面跳转到视频播放页面,并携带网络视频flag,效果图如图:

// IndexModule.ets
@Component
export struct VideoModule {
  private moduleName: string = '';

  build() {
    Column() {
      // 视频列表上方的文本信息
      ...
      // 视频列表组件
      List({ space: MARGIN_FONT_SIZE.FIRST_MARGIN }) {
        ForEach(HORIZONTAL_VIDEOS, (item: HorizontalVideoItem) => {
          ListItem() {
            HorizontalItem({
              imageSrc: item.image,
              source: NET,
              videoName: item.name
            })
          }
        }, (item: HorizontalVideoItem) => JSON.stringify(item))
      }
      // 设置列表横向排列
      .listDirection(Axis.Horizontal)
    }
    // 样式设置
    ...
  }
}

@Component
struct HorizontalItem {
  private imageSrc: Resource = $r('app.string.empty');
  private source: string = '';
  private videoName: string = '';

  build() {
    // 跳转二:使用route跳转到视频播放界面
    Column() {
      Image(this.imageSrc)
        .width(MARGIN_FONT_SIZE.SEVENTH_MARGIN)
        .height(MARGIN_FONT_SIZE.SIXTH_MARGIN)
        .onClick(() => {
          router.pushUrl({
            url: SECOND_PAGE,
            params: { source: this.source }
          });
        })
     ...
    }
    .justifyContent(FlexAlign.Center)
  }
}

在SimpleVideoIndex.ets主界面中引用SwiperVideo和VideoModule子组件。

// SimpleVideoIndex.ets
@Entry
@Component
struct SimpleVideoIndex {
  build() {
    Column({ space: MARGIN_FONT_SIZE.FOURTH_MARGIN }) {
      // 视频轮播组件
      SwiperVideo()
      List() {
        ForEach(LIST, (item: string) => {
          ListItem() {
            VideoModule({ moduleName: item })
              .margin({ top: MARGIN_FONT_SIZE.FIRST_MARGIN })
          }
        }, (item: string) => JSON.stringify(item))
      }
      .listDirection(Axis.Vertical)
      .margin({ top: MARGIN_FONT_SIZE.THIRD_MARGIN })
    }
    ...
  }
}

构建视频播放界面

VideoPlayer.ets其中定义了视频播放子组件VideoPlayer ,onPrepared回调方法中可以获取视频总时长,onUpdate回调方法中可实时获取到视频播放的当前时间戳,onFinish是视频播放结束后的回调方法,onError是视频播放出错的回调方法。

// VideoPlayer.ets
@Component
export struct VideoPlayer {
  private source: string | Resource = '';
  private controller: VideoController = new VideoController();
  private previewUris: Resource = $r('app.media.preview');
  @Provide currentTime: number = 0;
  @Provide durationTime: number = 0;
  @Provide durationStringTime: string = START_TIME;
  @Provide currentStringTime: string = START_TIME;
  @Consume isPlay: boolean;
  @Consume isOpacity: boolean;
  @Consume flag: boolean;
  @Consume isLoading: boolean;
  @Consume progressVal: number;

  build() {
    Column() {
      Video({
        src: this.source,
        previewUri: this.previewUris,
        controller: this.controller
      })
        .width(ALL_PERCENT)
        .height(STRING_PERCENT.NINETY_PERCENT)
        .controls(false)
        .autoPlay(false)
        .objectFit(ImageFit.Contain)
        .loop(false)
        .onUpdate((event) => {
          if (event) {
            this.currentTime = event.time;
            this.currentStringTime = changeSliderTime(this.currentTime);
          }
        })
        .onPrepared((event) => {
          this.prepared(event?.duration);
        })
        .onFinish(() => {
          this.finish();
        })
        .onError(() => {
          prompt.showToast({
            duration: COMMON_NUM_DURATION,
            message: MESSAGE
          });
        })
      VideoSlider({ controller: this.controller })
    }
  }
  ...
}

在自定义组件VideoPlayer底部使用了自定义子组件VideoSlider,VideoSlider自定义组件中显示和控制视频播放进度,效果图如图:

// VideoPlaySlider.ets
@Component
export struct VideoSlider {
  @Consume isOpacity: boolean;
  private controller: VideoController = new VideoController();
  @Consume currentStringTime: string;
  @Consume currentTime: number;
  @Consume durationTime: number;
  @Consume durationStringTime: string;
  @Consume isPlay: boolean;
  @Consume flag: boolean;
  @Consume isLoading: boolean;
  @Consume progressVal: number;

  build() {
    Row({ space: MARGIN_FONT_SIZE.FIRST_MARGIN }) {
      ...
      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) => {
          this.sliderOnchange(value, mode);
        })
      ...
    }
    .opacity(this.isOpacity ? DEFAULT_OPACITY : 1)
    ...
  }
  ...
}

在VideoController.ets中的视频控制和回调的相关方法。

// VideoControll.ets
export function changeSliderTime(value: number): string {
  let second: number = value % COMMON_NUM_MINUTE;
  let min: number = 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;
}

在SimpleVideoPlay.ets播放界面,引用VideoPlayer子组件,并在视频播放页面使用堆叠容器,在视频播放画面中心堆叠控制、视频加载图标,效果图如图:

// SimpleVideoPlay.ets
@Entry
@Component
struct Play {
  // 取到Index页面跳转来时携带的source对应的数据。
  private source: string = (router.getParams() as Record<string, Object>).source as string;
  private startIconResource: Resource = $r('app.media.ic_public_play');
  private backIconResource: Resource = $r('app.media.ic_back');
  @Provide isPlay: boolean = false;
  @Provide isOpacity: boolean = false;
  controller: VideoController = new VideoController();
  @Provide isLoading: boolean = false;
  @Provide progressVal: number = 0;
  @Provide flag: boolean = false;

  ...
  onPageHide() {
    this.controller.pause();
  }

  build() {
    Column() {
      // 顶部返回以及标题
    ...
      Stack() {
        // 不同的播放状态渲染不同得控制图片
        if (!this.isPlay && !this.isLoading) {
          Image(this.startIconResource)
            .width(MARGIN_FONT_SIZE.FIFTH_MARGIN)
            .height(MARGIN_FONT_SIZE.FIFTH_MARGIN)
            // 同一容器中兄弟组件显示层级关系,z值越大,显示层级越高 用于控制图片在视频上。
            .zIndex(STACK_STYLE.IMAGE_Z_INDEX)
        }
        if (this.isLoading) {
          Progress({
            value: STACK_STYLE.PROGRESS_VALUE,
            total: STACK_STYLE.PROGRESS_TOTAL,
            type: ProgressType.ScaleRing
          })
            .color(Color.Grey)
            .value(this.progressVal)
            .width(STACK_STYLE.PROGRESS_WIDTH)
            .style({
              strokeWidth: STACK_STYLE.PROGRESS_STROKE_WIDTH,
              scaleCount: STACK_STYLE.PROGRESS_SCALE_COUNT,
              scaleWidth: STACK_STYLE.PROGRESS_SCALE_WIDTH
            })
            .zIndex(STACK_STYLE.PROGRESS_Z_INDEX)
        }
        VideoPlayer({
          source: this.source,
          controller: this.controller
        })
          .zIndex(0)
      }
    }
    .height(ALL_PERCENT)
    .backgroundColor(Color.Black)
  }
}

本文主要是对鸿蒙开发中基础ArkTS语言的运用实操,更多的鸿蒙开发实操技术学习,可以前往主页学习更多的鸿蒙核心技术。下面是分享一份鸿蒙开发技术学习路线(略缩图)

高清完整版保存主页找我

最后

使用ArkTS语言实现视频播放器,主要包括主界面和视频播放界面,效果图如下:

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

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

相关文章

[RoarCTF 2019]Easy Java(java web)

题目 页面如下 页面长得像sql注入 点击help看一下 这里需要了解java web目录结构 WEB INF:Java的web应用安全目录&#xff1b; 此外如果想在页面访问WEB-INF应用里面的文件&#xff0c;必须要通过web.xml进行相应的映射才能访问&#xff1b; WEB-INF是Java Web应用程序中的一…

Java连接Mysql报错:javax.net.ssl.SSLException: Received fatal alert: internal_error

大致报错日志如下&#xff1a; The last packet successfully received from the server was 11 milliseconds ago. The last packet sent successfully to the server was 10 milliseconds ago.at sun.reflect.GeneratedConstructorAccessor275.newInstance(Unknown Source)…

Collections

Collections Collections四种对集合进行排序的方式 方法名说明public static <T extends Comparable<? super T>> void sort (List<T> list)排序public static void reverse(List<?> list)逆序public static void shuffle(List<?> list)随机…

scanf函数返回值占位符详解,%*,%[]的应用

前言 scanf函数可以说是我们一开始就会接触的函数了&#xff0c;但在最近复习时我又找到而来一些之前不甚了解或是块要遗忘的知识&#xff0c;特作此篇。 一.返回值 我们之前提到了scanf返回值被忽略的问题&#xff1a; scanf函数返回值被忽略-CSDN博客 那么scanf的返回值…

Unity JSON编码解码之LitJson 深度剖析

把LitJson的代码库放入到项目中&#xff0c;如图所示:JSON在游戏开发中是一种序列化/反序列化常用的技术&#xff0c;把游戏相关的数据,如地图组成,通过JSON编码&#xff0c;序列化成JSON文本&#xff0c;传输或存储, 要使用的时候再通过JSON技术把文本解析成数据对象&#xff…

Word 将页面方向更改为横向或纵向

文章目录 更改整个文档的方向更改部分页面的方向方法1&#xff1a;方法2&#xff1a; 参考链接 更改整个文档的方向 选择“布局”>“方向”&#xff0c;选择“纵向”或“横向”。 更改部分页面的方向 需要达到下图结果&#xff1a; 方法1&#xff1a; 选:中你要在横向页面…

ThreadLocal为什么存在内存泄漏,源码分析

文章目录 1. ThreadLocal的使用场景2. 弱引用与内存泄露3. 源码分析①&#xff1a;ThreadLocalMap②&#xff1a;set操作③&#xff1a;get操作④&#xff1a;remove操作 4. 继承性 InheritableThreadLocal5. 各类ThreadLocal问题总结 1. ThreadLocal的使用场景 通常&#xff0…

计算机网络复习6

应用层 文章目录 应用层网络应用模型域名系统DNS文件传输协议FTP电子邮件万维网 网络应用模型 客户/服务器模型 客户/服务器&#xff08;Client/Server&#xff0c;C/S)模型中&#xff0c;有一个总是打开的主机称为服务器&#xff0c;它服务于许多来自其他称为客户机的主机请求…

SparkStreaming_window_sparksql_reids

1.5 window 滚动窗口滑动窗口 window操作就是窗口函数。Spark Streaming提供了滑动窗口操作的支持&#xff0c;从而让我们可以对一个滑动窗口内的数据执行计算操作。每次掉落在窗口内的RDD的数据&#xff0c;会被聚合起来执行计算操作&#xff0c;然后生成的RDD&#xff0c;会…

Stable Diffusion WebUI安装合成面部说话插件SadTalker

SadTalker可以根据一张图片、一段音频&#xff0c;合成面部说这段语音的视频。图片需要真人或者接近真人。 安装ffmpeg 下载地址&#xff1a; https://www.gyan.dev/ffmpeg/builds/ 下载ffmpeg-git-full.7z 后解压&#xff0c;将解压后的目录\bin添加到环境变量的Path中。 在…

鸿蒙原生应用再添新丁!爱奇艺入局鸿蒙

鸿蒙原生应用再添新丁&#xff01;爱奇艺 入局鸿蒙 来自 HarmonyOS 微博12月29日消息&#xff0c;#爱奇艺完成鸿蒙原生应用Beta版#作为中国头部在线视频平台&#xff0c;爱奇艺 完成鸿蒙原生应用Beta版&#xff0c;将以丰富的正版高清视频资源促进鸿蒙生态的进一步繁荣&#x…

python实现图像的二维傅里叶变换——冈萨雷斯数字图像处理

原理 二维傅里叶变换是一种在图像处理中常用的数学工具&#xff0c;它将图像从空间域&#xff08;我们通常看到的像素排列&#xff09;转换到频率域。这种变换揭示了图像的频率成分&#xff0c;有助于进行各种图像分析和处理&#xff0c;如滤波、图像增强、边缘检测等。 在数学…

YOLOv5算法进阶改进(10)— 更换主干网络之MobileViTv3 | 轻量化Backbone

前言:Hello大家好,我是小哥谈。MobileViTv3是一种改进的模型架构,用于图像分类任务。它是在MobileViTv1和MobileViTv2的基础上进行改进的,通过引入新的模块和优化网络结构来提高性能。本节课就给大家介绍一下如何在主干网络中引入MobileViTv3网络结构,希望大家学习之后能够…

Stable Diffusion WebUI制作光影文字效果

在huggingface上下载control_v1p_sd15_brightness模型。 将模型放在stable-diffusion-webui\extensions\sd-webui-controlnet\models目录下。 SD参数配置 正向提示词&#xff1a; city,Building,tall building,Neon Light, gentle light shines through, anime style, paint…

冒泡排序--------(C每日一题)

冒泡排序&#xff1a; 每次将相邻的两个数比较,将小的调到前头--升序 冒泡排序一个结论&#xff1a; n个数要进行n-1轮比较&#xff0c;第j轮要进行n-j次两两比较 循环体代码&#xff1a; int main() {int i, j,n,a[10],t;//n是几个数比较for(j1;j<n-1;j)//控制轮次for…

PNG免抠素材库,免费下载,可商用~

本期分享5个高质量PNG素材网站&#xff0c;让你在工作中大大提高效率&#xff0c;节省更多的时间&#xff0c;赶紧收藏起来吧~ 1、菜鸟图库 https://www.sucai999.com/searchlist/66008----all-0-1.html?vNTYxMjky 网站主要分享设计素材为主。像平面海报、免抠元素、背景图片…

英语打卡分析12

[爱心]长难句分享第十二天解析 [玫瑰]【词汇】&#xff1a; • appropriate [əˈproʊpriət] adj. 恰当的 • in place 准备妥当 • caregiver [ˈkerɡɪvər] n. 看护人 • no more … than… 和……一样不 • newsworthy [ˈnuːzwɜːri] adj. 值得报道的 • capable […

记一次应急响应练习(Linux)

记一次应急响应练习(Linux) Linux&#xff1a; 请提交攻击者的IP地址 答&#xff1a; 192.168.31.132 思路&#xff1a; 通过查看历史命令和开放的8080端口看到这台主机上运行的是Tomcat服务。并且在历史命令中看到了Tomcat的安装路径。那么就算是找到了日志的查看点了&#x…

SpringBoot3 核心技能

1. 常用注解 SpringBoot摒弃XML配置方式&#xff0c;改为全注解驱动 1. 组件注册 Configuration、SpringBootConfiguration Bean、Scope Controller、 Service、Repository、Component Import ComponentScan 步骤&#xff1a; 1、Configuration 编写一个配置类 2、在…

中科院1区TOP,Elsevier出版社,均1-2个月录用!检索超稳!

【SciencePub学术】本期&#xff0c;小编给大家推荐的是一本Elsevier旗下、工程技术领域、影响因子为6.0的中科院1区TOP。其详情如下&#xff1a; 期刊简介 TRIBOLOGY INTERNATIONAL ISSN&#xff1a;0301-679X E-ISSN&#xff1a;1879-2464 IF&#xff08;2022&#x…