概述
在手機(jī)、平板或是智慧屏這些終端設(shè)備上,媒體功能可以算作是我們最常用的場景之一。無論是實(shí)現(xiàn)音頻的播放、錄制、采集,還是視頻的播放、切換、循環(huán),亦或是相機(jī)的預(yù)覽、拍照等功能,媒體組件都是必不可少的。以視頻功能為例,在應(yīng)用開發(fā)過程中,我們需要通過ArkUI提供的Video組件為應(yīng)用增加基礎(chǔ)的視頻播放功能。借助Video組件,我們可以實(shí)現(xiàn)視頻的播放功能并控制其播放狀態(tài)。常見的視頻播放場景包括觀看網(wǎng)絡(luò)上的較為流行的短視頻,也包括查看我們存儲在本地的視頻內(nèi)容。
本文將結(jié)合《簡易視頻播放器(ArkTS)》這個(gè)Codelab,對Video組件的參數(shù)、屬性及事件進(jìn)行介紹,然后通過組件的屬性調(diào)用和事件回調(diào)闡明Video組件的基本使用方法,最后結(jié)合Video組件使用過程中的常見問題講解自定義控制器的使用。
Video組件用法介紹
Video組件參數(shù)介紹 Video組件的接口表達(dá)形式為:
- Video(value: {src?: string | Resource, currentProgressRate?: number | string |PlaybackSpeed, previewUri?: string |PixelMap | Resource, controller?: VideoController})
其中包含四個(gè)可選參數(shù),src、currentProgressRate、previewUri和controller。
- src表示視頻播放源的路徑,可以支持本地視頻路徑和網(wǎng)絡(luò)路徑。使用網(wǎng)絡(luò)地址時(shí),如https,需要注意的是需要在module.json5文件中申請網(wǎng)絡(luò)權(quán)限。在使用本地資源播放時(shí),當(dāng)使用本地視頻地址我們可以使用媒體庫管理模塊medialibrary來查詢公共媒體庫中的視頻文件,示例代碼如下:
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
async queryMediaVideo() {
let option = {
// 根據(jù)媒體類型檢索
selections: mediaLibrary.FileKey.MEDIA_TYPE + '=?',
// 媒體類型為視頻
selectionArgs: [mediaLibrary.MediaType.VIDEO.toString()]
};
let media = mediaLibrary.getMediaLibrary(getContext(this));
// 獲取資源文件
const fetchFileResult = await media.getFileAssets(option);
// 以獲取的第一個(gè)文件為例獲取視頻地址
let fileAsset = await fetchFileResult.getFirstObject();
this.source = fileAsset.uri
}
為了方便功能演示,示例中媒體資源需存放在resources下的rawfile文件夾里。
- currentProgressRate表示視頻播放倍速,其參數(shù)類型為number,取值支持0.75,1.0,1.25,1.75,2.0,默認(rèn)值為1.0倍速;
- previewUri表示視頻未播放時(shí)的預(yù)覽圖片路徑;
- controller表示視頻控制器。
參數(shù)的具體描述如下表:
參數(shù)名 | 參數(shù)類型 | 必填 |
---|---|---|
src | string | Resource |
currentProgressRate | number | string |
previewUri | string | PixelMap8+ |
controller | VideoController | 否 |
說明
視頻支持的規(guī)格是:mp4、mkv、webm、TS。 下面我們通過具體的例子來說明參數(shù)的使用方法,我們選擇播放本地視頻,視頻未播放時(shí)的預(yù)覽圖片路徑也為本地,代碼實(shí)現(xiàn)如下:
@Component
export struct VideoPlayer {
private source: string | Resource;
private controller: VideoController;
private previewUris: Resource = $r('app.media.preview');
...
build() {
Column() {
Video({
src: this.source,
previewUri: this.previewUris,
controller: this.controller
})
...
VideoSlider({ controller: this.controller })
}
}
}
效果如下:
Video組件屬性介紹
除了支持組件的尺寸設(shè)置、位置設(shè)置等通用屬性外,Video組件還支持是否靜音、是否自動播放、控制欄是否顯示、視頻顯示模式以及單個(gè)視頻是否循環(huán)播放五個(gè)私有屬性。
名稱 | 參數(shù)類型 | 描述 |
---|---|---|
muted | boolean | 是否靜音。默認(rèn)值:false |
autoPlay | boolean | 是否自動播放。默認(rèn)值:false |
controls | boolean | 控制視頻播放的控制欄是否顯示。默認(rèn)值:true |
objectFit | ImageFit | 設(shè)置視頻顯示模式。默認(rèn)值:Cover |
loop | boolean | 是否單個(gè)視頻循環(huán)播放。默認(rèn)值:false |
其中,objectFit 中視頻顯示模式包括Contain、Cover、Auto、Fill、ScaleDown、None 6種模式,默認(rèn)情況下使用ImageFit.Cover(保持寬高比進(jìn)行縮小或者放大,使得圖片兩邊都大于或等于顯示邊界),其他效果(如自適應(yīng)顯示、保持原有尺寸顯示、不保持寬高比進(jìn)行縮放等)可以根據(jù)具體使用場景/設(shè)備來進(jìn)行選擇。 在Codelab示例中體現(xiàn)了controls、autoplay和loop屬性的配置,示例代碼如下:
@Component
export struct VideoPlayer {
private source: string | Resource;
private controller: VideoController;
...
build() {
Column() {
Video({
controller: this.controller
})
.controls(false) //不顯示控制欄
.autoPlay(false) // 手動點(diǎn)擊播放
.loop(false) // 關(guān)閉循環(huán)播放
...
}
}
}
效果如下:
Video組件回調(diào)事件介紹
Video組件能夠支持常規(guī)的點(diǎn)擊、觸摸等通用事件,同時(shí)也支持onStart、onPause、onFinish、onError等事件,具體事件的功能描述見下表:
事件名稱 | 功能描述 |
---|---|
onStart(event:() => void) | 播放時(shí)觸發(fā)該事件。 |
onPause(event:() => void) | 暫停時(shí)觸發(fā)該事件。 |
onFinish(event:() => void) | 播放結(jié)束時(shí)觸發(fā)該事件。 |
onError(event:() => void) | 播放失敗時(shí)觸發(fā)該事件。 |
onPrepared(callback:(event?: { duration: number }) => void) | 視頻準(zhǔn)備完成時(shí)觸發(fā)該事件,通過duration可以獲取視頻時(shí)長,單位為s。 |
onSeeking(callback:(event?: { time: number }) => void) | 操作進(jìn)度條過程時(shí)上報(bào)時(shí)間信息,單位為s。 |
onSeeked(callback:(event?: { time: number }) => void) | 操作進(jìn)度條完成后,上報(bào)播放時(shí)間信息,單位為s。 |
onUpdate(callback:(event?: { time: number }) => void) | 播放進(jìn)度變化時(shí)觸發(fā)該事件,單位為s,更新時(shí)間間隔為250ms。 |
onFullscreenChange(callback:(event?: { fullscreen: boolean }) => void) | 在全屏播放與非全屏播放狀態(tài)之間切換時(shí)觸發(fā)該事件 |
在Codelab中我們以更新事件、準(zhǔn)備事件、失敗事件以及點(diǎn)擊事件為回調(diào)為例進(jìn)行演示,代碼實(shí)現(xiàn)如下:
Video({ ... })
.onUpdate((event) = > {
this.currentTime = event.time;
this.currentStringTime = changeSliderTime(this.currentTime); //更新事件
})
.onPrepared((event) = > {
prepared.call(this, event); //準(zhǔn)備事件
})
.onError(() = > {
prompt.showToast({
duration: COMMON_NUM_DURATION, //播放失敗事件
message: MESSAGE
});
...
})
其中,onUpdate更新事件在播放進(jìn)度變化時(shí)觸發(fā),從event中可以獲取當(dāng)前播放進(jìn)度,從而更新進(jìn)度條顯示事件,比如視頻播放時(shí)間從24秒更新到30秒。onError事件在視頻播放失敗時(shí)觸發(fā),在CommonConstants.ets中定義了常量類MESSAGE,所以在視頻播放失敗時(shí)會顯示“請檢查網(wǎng)絡(luò)”。
- const MESSAGE: string = '請檢查網(wǎng)絡(luò)'
自定義控制器的組成與實(shí)現(xiàn)
自定義控制器的組成
Video組件的原生控制器樣式相對固定,當(dāng)我們對頁面的布局色調(diào)的一致性有所要求,或者在拖動進(jìn)度條的同時(shí)需要顯示其百分比進(jìn)度時(shí),原生控制器就無法滿足需要了。如下圖右側(cè)的效果需要使用自定義控制器實(shí)現(xiàn),接下來我們看一下自定義控制器的組成。
為了實(shí)現(xiàn)自定義控制器的進(jìn)度顯示等功能,我們需要通過Row容器實(shí)現(xiàn)控制器的整體布局,然后借由Text組件來顯示視頻的播放起始時(shí)間、進(jìn)度時(shí)間以及視頻總時(shí)長,最后通過滑動進(jìn)度條Slider組件來實(shí)現(xiàn)視頻進(jìn)度條的效果,代碼如下:
@Component
export struct VideoSlider {
...
build() {
Row(...) {
Image(...)
Text(...)
Slider(...)
Text(...)
}
...
}
}
自定義控制器的實(shí)現(xiàn)
自定義控制器容器內(nèi)嵌套了視頻播放時(shí)間Text組件、滑動器Slider組件以及視頻總時(shí)長Text組件 3個(gè)橫向排列的組件,其中Text組件在之前的基礎(chǔ)組件課程中已經(jīng)有過詳細(xì)介紹,這里就不再進(jìn)行贅述。需要強(qiáng)調(diào)的是兩個(gè)Text組件顯示的時(shí)長是由Slider組件的onChange(callback: (value: number, mode: SliderChangeMode) => void)回調(diào)事件來進(jìn)行傳遞的,而Text組件的數(shù)值與視頻播放進(jìn)度數(shù)值value則是通過@Provide與 @Consume裝飾器進(jìn)行的數(shù)據(jù)聯(lián)動,實(shí)現(xiàn)效果可見圖片下方黑色控制欄部分,具體代碼步驟及代碼如下: 獲取/計(jì)算視頻時(shí)長
export function prepared(event) {
this.durationTime = event.duration;
let second: number = event.duration % COMMON_NUM_MINUTE;
let min: number = parseInt((event.duration / COMMON_NUM_MINUTE).toString());
let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min;
let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second;
this.durationStringTime = `${head}${SPLIT}${end}`;
...
};
設(shè)置進(jìn)度條參數(shù)及屬性
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) = > {...})
計(jì)算當(dāng)前進(jìn)度播放時(shí)間及添加onUpdate回調(diào) 最后,在我們播放視頻時(shí)還需要更新顯示播放的時(shí)間進(jìn)度,也就是左側(cè)的Text組件。在視頻開始播放前,播放時(shí)間默認(rèn)為00:00,隨著視頻播放,時(shí)間需要不斷更新為當(dāng)前進(jìn)度時(shí)間。所以左側(cè)的Text組件我們不僅需要讀取時(shí)間,還需要為其添加數(shù)據(jù)聯(lián)動。這里,我們就是通過為Video組件添加onUpdate事件來實(shí)現(xiàn)的,在視頻播放過程中會不斷調(diào)用changeSliderTime方法獲取當(dāng)前的播放時(shí)間并進(jìn)行計(jì)算及單位轉(zhuǎn)化,從而不斷刷新進(jìn)度條的值,也就是控制器左側(cè)的播放進(jìn)度時(shí)間Text組件。
Video({...})
...
.onUpdate((event) = > {
this.currentTime = event.time;
this.currentStringTime = changeSliderTime(this.currentTime)
})
export function changeSliderTime(value: number): string {
let second: number = value % COMMON_NUM_MINUTE;
let min: 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;
};
指定視頻播放進(jìn)度及添加onChange事件回調(diào) 如需手動進(jìn)行進(jìn)度條的拖動,則需要在Slider組件中指定播放進(jìn)度,并為Slider組件添加onChange事件回調(diào)。Slider滑動時(shí)就會觸發(fā)該事件回調(diào),從而實(shí)現(xiàn)將視頻定位到進(jìn)度條當(dāng)前刷新位置,完成時(shí)長組件渲染與視頻播放進(jìn)度數(shù)據(jù)聯(lián)動。
Slider({...})
.onChange((value: number, mode: SliderChangeMode) = > {
sliderOnchange.call(this, value, mode);
})
export function sliderOnchange(value: number, mode: SliderChangeMode) {
this.currentTime = parseInt(value.toString());
this.controller.setCurrentTime(parseInt(value.toString()), SeekMode.Accurate);
...
};
到這里我們就實(shí)現(xiàn)了自定義控制器的構(gòu)建,兩個(gè)Text組件顯示的時(shí)長是由Slider組件的onChange回調(diào)事件來進(jìn)行傳遞的,而Text組件的數(shù)值與視頻播放進(jìn)度數(shù)值value則通過是onUpdate與onChange事件并借由@Provide @Consume裝飾器進(jìn)行的數(shù)據(jù)聯(lián)動。
審核編輯 黃宇
-
存儲
+關(guān)注
關(guān)注
13文章
4328瀏覽量
85942 -
鴻蒙
+關(guān)注
關(guān)注
57文章
2369瀏覽量
42900
發(fā)布評論請先 登錄
相關(guān)推薦
評論