赞
踩
主界面由视频轮播模块和多个视频列表模块组成,效果图如图:
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语言实现视频播放器,主要包括主界面和视频播放界面,效果图如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。