概述
在手機、平板或是智慧屏這些終端設備上,媒體功能可以算作是我們最常用的場景之一。無論是實現音頻的播放、錄制、采集,還是視頻的播放、切換、循環,亦或是相機的預覽、拍照等功能,媒體組件都是必不可少的。以視頻功能為例,在應用開發過程中,我們需要通過ArkUI提供的Video組件為應用增加基礎的視頻播放功能。借助Video組件,我們可以實現視頻的播放功能并控制其播放狀態。常見的視頻播放場景包括觀看網絡上的較為流行的短視頻,也包括查看我們存儲在本地的視頻內容。
Video組件用法介紹
Video組件參數介紹
Video組件的接口表達形式為:
Video(value: {src?: string | Resource, currentProgressRate?: number | string |PlaybackSpeed, previewUri?: string |PixelMap | Resource, controller?: VideoController})
其中包含四個可選參數,src、currentProgressRate、previewUri和controller。
- src表示視頻播放源的路徑,可以支持本地視頻路徑和網絡路徑。使用網絡地址時,如https,需要注意的是需要在module.json5文件中申請網絡權限。在使用本地資源播放時,當使用本地視頻地址我們可以使用媒體庫管理模塊medialibrary來查詢公共媒體庫中的視頻文件,示例代碼如下:
import mediaLibrary from '@ohos.multimedia.mediaLibrary';async queryMediaVideo() {let option = {// 根據媒體類型檢索selections: mediaLibrary.FileKey.MEDIA_TYPE + '=?',// 媒體類型為視頻selectionArgs: [mediaLibrary.MediaType.VIDEO.toString()]};let media = mediaLibrary.getMediaLibrary(getContext(this));// 獲取資源文件const fetchFileResult = await media.getFileAssets(option);// 以獲取的第一個文件為例獲取視頻地址let fileAsset = await fetchFileResult.getFirstObject();this.source = fileAsset.uri
}
為了方便功能演示,示例中媒體資源需存放在resources下的rawfile文件夾里。
- currentProgressRate表示視頻播放倍速,其參數類型為number,取值支持0.75,1.0,1.25,1.75,2.0,默認值為1.0倍速;
- previewUri表示視頻未播放時的預覽圖片路徑;
- controller表示視頻控制器。
參數的具體描述如下表:
下面我們通過具體的例子來說明參數的使用方法,我們選擇播放本地視頻,視頻未播放時的預覽圖片路徑也為本地,代碼實現如下:
@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組件屬性介紹
除了支持組件的尺寸設置、位置設置等通用屬性外,Video組件還支持是否靜音、是否自動播放、控制欄是否顯示、視頻顯示模式以及單個視頻是否循環播放五個私有屬性。
其中,objectFit 中視頻顯示模式包括Contain、Cover、Auto、Fill、ScaleDown、None 6種模式,默認情況下使用ImageFit.Cover(保持寬高比進行縮小或者放大,使得圖片兩邊都大于或等于顯示邊界),其他效果(如自適應顯示、保持原有尺寸顯示、不保持寬高比進行縮放等)可以根據具體使用場景/設備來進行選擇。
在Codelab示例中體現了controls、autoplay和loop屬性的配置,示例代碼如下:
@Component
export struct VideoPlayer {private source: string | Resource;private controller: VideoController;...build() {Column() {Video({controller: this.controller}).controls(false) //不顯示控制欄 .autoPlay(false) // 手動點擊播放 .loop(false) // 關閉循環播放 ...}}
}
Video組件回調事件介紹
Video組件能夠支持常規的點擊、觸摸等通用事件,同時也支持onStart、onPause、onFinish、onError等事件,具體事件的功能描述見下表:
在Codelab中我們以更新事件、準備事件、失敗事件以及點擊事件為回調為例進行演示,代碼實現如下:
Video({ ... }).onUpdate((event) => {this.currentTime = event.time;this.currentStringTime = changeSliderTime(this.currentTime); //更新事件 }).onPrepared((event) => {prepared.call(this, event); //準備事件 }).onError(() => {prompt.showToast({duration: COMMON_NUM_DURATION, //播放失敗事件 message: MESSAGE});...})
其中,onUpdate更新事件在播放進度變化時觸發,從event中可以獲取當前播放進度,從而更新進度條顯示事件,比如視頻播放時間從24秒更新到30秒。onError事件在視頻播放失敗時觸發,在CommonConstants.ets中定義了常量類MESSAGE,所以在視頻播放失敗時會顯示“請檢查網絡”。
const MESSAGE: string = '請檢查網絡'
自定義控制器的組成與實現
自定義控制器的組成
Video組件的原生控制器樣式相對固定,當我們對頁面的布局色調的一致性有所要求,或者在拖動進度條的同時需要顯示其百分比進度時,原生控制器就無法滿足需要了。如下圖右側的效果需要使用自定義控制器實現,接下來我們看一下自定義控制器的組成。
為了實現自定義控制器的進度顯示等功能,我們需要通過Row容器實現控制器的整體布局,然后借由Text組件來顯示視頻的播放起始時間、進度時間以及視頻總時長,最后通過滑動進度條Slider組件來實現視頻進度條的效果,代碼如下:
@Component
export struct VideoSlider {...build() {Row(...) {Image(...)Text(...)Slider(...)Text(...)}...}
}
自定義控制器的實現
自定義控制器容器內嵌套了視頻播放時間Text組件、滑動器Slider組件以及視頻總時長Text組件 3個橫向排列的組件,其中Text組件在之前的基礎組件課程中已經有過詳細介紹,這里就不再進行贅述。需要強調的是兩個Text組件顯示的時長是由Slider組件的onChange(callback: (value: number, mode: SliderChangeMode) => void)回調事件來進行傳遞的,而Text組件的數值與視頻播放進度數值value則是通過@Provide與 @Consume裝飾器進行的數據聯動,實現效果可見圖片下方黑色控制欄部分,具體代碼步驟及代碼如下:
獲取/計算視頻時長
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}`;...
};
設置進度條參數及屬性
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) => {...})
計算當前進度播放時間及添加onUpdate回調
最后,在我們播放視頻時還需要更新顯示播放的時間進度,也就是左側的Text組件。在視頻開始播放前,播放時間默認為00:00,隨著視頻播放,時間需要不斷更新為當前進度時間。所以左側的Text組件我們不僅需要讀取時間,還需要為其添加數據聯動。這里,我們就是通過為Video組件添加onUpdate事件來實現的,在視頻播放過程中會不斷調用changeSliderTime方法獲取當前的播放時間并進行計算及單位轉化,從而不斷刷新進度條的值,也就是控制器左側的播放進度時間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;
};
指定視頻播放進度及添加onChange事件回調
如需手動進行進度條的拖動,則需要在Slider組件中指定播放進度,并為Slider組件添加onChange事件回調。Slider滑動時就會觸發該事件回調,從而實現將視頻定位到進度條當前刷新位置,完成時長組件渲染與視頻播放進度數據聯動。
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);...
};
到這里我們就實現了自定義控制器的構建,兩個Text組件顯示的時長是由Slider組件的onChange回調事件來進行傳遞的,而Text組件的數值與視頻播放進度數值value則通過是onUpdate與onChange事件并借由@Provide @Consume裝飾器進行的數據聯動。