無論是從視頻播放頁面進入全屏播放頁面,還是由全屏播放頁面返回到視頻播放頁面,只要處于播放在,就會同步播放時間,在頁面切換后繼續播放視頻。當然,在全屏播放時頁面處于橫屏,返回到視頻播放頁面界面則切換回豎屏。

??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區??
??https://ost.51cto.com??
效果
??在線視頻??
接??上一篇??,視頻播放頁面屬于小屏顯示,為了讓觀演效果更好,可以選擇全屏播放,全屏播放時界面由豎屏轉為橫屏顯示,并且可以雙向同步觀影時間,無論是從視頻播放頁面進入全屏播放頁面,還是由全屏播放頁面返回到視頻播放頁面,只要處于播放在,就會同步播放時間,在頁面切換后繼續播放視頻。當然,在全屏播放時頁面處于橫屏,返回到視頻播放頁面界面則切換回豎屏,我們來看下設計圖:


從設計圖上看,全屏播放頁面的布局很簡單,我們在上一節總已經將視頻播放視圖封裝成了一個子組件—VideoView.ets,我們只要將其加載到全屏播放頁面即可。
項目開發
開發環境
硬件平臺:DAYU2000 RK3568
系統版本:OpenHarmony 3.2 beta5
SDK:9(3.2.10.6)
IDE:DevEco Studio 3.1 Beta1 Build Version: 3.1.0.200, built on February 13, 2023
程序代碼
1、FullScreen.ets
/**
* 全屏播放
*/
import emitter from '@ohos.events.emitter';
import { CommonData } from '../model/CommonData'
import router from '@ohos.router';
import { VideoView } from '../view/VideoView';
import { VideoData } from '../model/VideoData'
import { VideoDataUtils } from '../utils/VideoDataUtils'
import { VideoSpeed } from '../model/VideoSpeed'
import { PLAYBACK_SPEED, PLAYBACK_STATE } from '../model/Playback'
const TAG: string = 'VideoFullScreen'
@Entry
@Component
struct VideoFullScreen {
@State mTag: string = TAG
@State mVideoData: VideoData = null
private name: string
@State uri: any = null
@State previewImage: any = null
private actors: string | Resource
private directs: string | Resource
private introduction: string
@State videoState: string = PLAYBACK_STATE.INIT
@Provide('play_time') curTime: number = 0
@State rateIndex: number = 1
@State rate: VideoSpeed = PLAYBACK_SPEED[1]
@Provide('show_operation') isShowOperation : boolean = true
aboutToAppear() {
// 橫屏顯示
emitter.emit({
eventId: CommonData.EVENT_WINDOW_LANDSCAPE_ID
})
this.initData()
}
initData() {
// 獲取當前需要播放的電影資源信息
this.mVideoData = router.getParams()['video_data']
this.name = this.mVideoData.name
this.uri = this.mVideoData.uri
this.previewImage = this.mVideoData.image
this.actors = VideoDataUtils.getUser(this.mVideoData.actors)
this.directs = VideoDataUtils.getUser(this.mVideoData.directs)
this.introduction = this.mVideoData.introduction
this.curTime = router.getParams()['cur_time']
this.videoState = router.getParams()['video_state']
console.info(`${TAG} curTime:${this.curTime} videoState:${this.videoState}`)
}
onBackPress() {
console.info(`${TAG} onBackPress`)
this.sendPlayVideo()
}
onScreen(isFull: boolean) {
console.info(`${TAG} onScreen ${isFull}`)
if (!isFull) {
this.goBack()
}
}
sendPlayVideo() {
console.info(`${TAG} sendPlayVideo`)
emitter.emit({
eventId: CommonData.EVENT_PLAY_VIDEO
}, {
data: {
cur_time: this.curTime,
video_state: this.videoState
}
})
}
goBack() {
this.sendPlayVideo()
router.back()
}
aboutToDisappear() {
}
build() {
Stack({
alignContent: Alignment.TopStart
}) {
VideoView({
_TAG: this.mTag,
videoUri: $uri,
previewUri: $previewImage,
videoRate: $rate,
videoRateIndex: $rateIndex,
onScreen: this.onScreen.bind(this),
videoState: $videoState,
isFullScreen: true,
isEvent: false,
mWidth: '100%',
mHeight: '100%'
})
if (this.isShowOperation) {
Row({ space: 10 }) {
Image($r('app.media.icon_back'))
.width(24)
.height(24)
.objectFit(ImageFit.Cover)
.onClick(() => {
this.goBack()
})
Text(this.name)
.fontSize(20)
.fontColor(Color.White)
}
.padding(20)
}
}
.width('100%')
.height('100%')
}
}
界面代碼非常簡單,所有的功能在集成在VideoView組件中,這與視頻播放頁面相比,增加了電影播放倍數的選擇,選擇器使用??Select??下拉選擇菜單實現,下面我們來詳細的介紹下這個組件。
Select
提供了下拉選擇菜單,讓用戶在多個選項之間選擇。
Select(options: Array<SelectOption>)
SelectOption對象說明:參數名 | 參數類型 | 必填 | 參數描述 |
value | ResourceStr | 是 | 下拉選項內容。 |
icon | ResourceStr | 否 | 下拉選項圖片。 |
屬性:名稱 | 參數類型 | 描述 |
selected | number | 設置下拉菜單初始選項的索引,第一項的索引為0。 當不設置selected屬性時,默認選擇值為-1,菜單項不選中。 |
value | string | 設置下拉按鈕本身的文本內容。 |
font | Font | 設置下拉按鈕本身的文本樣式。 |
fontColor | ResourceColor | 設置下拉按鈕本身的文本顏色。 |
selectedOptionBgColor | ResourceColor | 設置下拉菜單選中項的背景色。 |
selectedOptionFont | Font | 設置下拉菜單選中項的文本樣式。 |
selectedOptionFontColor | ResourceColor | 設置下拉菜單選中項的文本顏色。 |
optionBgColor | ResourceColor | 設置下拉菜單項的背景色。 |
optionFont | Font | 設置下拉菜單項的文本樣式。 |
optionFontColor | ResourceColor | 設置下拉菜單項的文本顏色。 |
事件:名稱 | 功能描述 |
onSelect(callback: (index: number, value?: string) => void) | 下拉菜單選中某一項的回調。<br/>index:選中項的索引。<br/>value:選中項的值。 |
本案例中的Select組件是在VideoView.ets視頻播放子組件中實現的,核心代碼如下:
VideoView.ets
if (this.isFullScreen) {
Select(this.selectSpeedOption)
.selected(this.videoRateIndex)
.value(this.videoRate.val)
.font({ size: 10 })
.fontColor(Color.White)
.selectedOptionFont({ size: 10 })
.selectedOptionFontColor('#F54F02')
.optionFontColor('#5E5E5E')
.optionFont({ size: 10 })
.onSelect((index: number) => {
console.info('Select:' + index)
this.videoRate = PLAYBACK_SPEED[index]
this.videoRateIndex = index
console.info(`${TAG} videoRateIndex = ${this.videoRateIndex}`)
})
.border({
width: 0,
color: Color.White
})
}
2、橫豎屏切換
如何實現橫豎屏切換:首先我們知道由于的界面需要集成到一個窗口上,這個窗口就是Window,在應用啟動時會觸發UIAbility的生命周期方法onWindowStageCreate(),此接口的回調中帶有一個參數就是WindowStage窗口管理器,窗口管理器可以通過getMainWindow()接口獲取到主窗口,返回當前窗口的實例Window,得到窗口實例后就可以通過setPreferredOrientation()設置窗口的顯示方向。
setPreferredOrientation:setPreferredOrientation(orientation: Orientation, callback: AsyncCallback<void" style="font: revert; -webkit-font-smoothing: antialiased; margin: 0px; padding: 0px; border: 0px; vertical-align: baseline; color: rgb(166, 127, 89); cursor: help;">>): void
設置窗口的顯示方向屬性,使用callback異步回調。
參數:
參數名 | 類型 | 必填 | 說明 |
Orientation | Orientation | 是 | 窗口顯示方向的屬性。 |
callback | AsyncCallback<void> | 是 | 回調函數。 |
Orientation:窗口顯示方向類型枚舉。
名稱 | 值 | 說明 |
UNSPECIFIED | 0 | 表示未定義方向模式,由系統判定。 |
PORTRAIT | 1 | 表示豎屏顯示模式。 |
LANDSCAPE | 2 | 表示橫屏顯示模式。 |
PORTRAIT_INVERTED | 3 | 表示反向豎屏顯示模式。 |
LANDSCAPE_INVERTED | 4 | 表示反向橫屏顯示模式。 |
AUTO_ROTATION | 5 | 表示傳感器自動旋轉模式。 |
AUTO_ROTATION_PORTRAIT | 6 | 表示傳感器自動豎向旋轉模式。 |
AUTO_ROTATION_LANDSCAPE | 7 | 表示傳感器自動橫向旋轉模式。 |
AUTO_ROTATION_RESTRICTED | 8 | 表示受開關控制的自動旋轉模式。 |
AUTO_ROTATION_PORTRAIT_RESTRICTED | 9 | 表示受開關控制的自動豎向旋轉模式。 |
AUTO_ROTATION_LANDSCAPE_RESTRICTED | 10 | 表述受開關控制的自動橫向旋轉模式。 |
LOCKED | 11 | 表示鎖定模式。 |
具體如何實現呢?
我們知道由于啟動時會加重UIAbility,在項目中EntryAbility繼承UIAbility,所以可以在EntryAbility.ts中獲取Window實例設置其窗口顯示方向來實現橫豎屏切換,代碼如下:
import UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import emitter from '@ohos.events.emitter';
import { CommonData } from '../model/CommonData'
export default class EntryAbility extends UIAbility {
private mWindow : window.Window
onCreate(want, launchParam) {
}
onDestroy() {
// 設置豎屏
this.mWindow.setPreferredOrientation(window.Orientation.PORTRAIT)
this.unregisterEmitter()
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
this.mWindow = windowStage.getMainWindowSync()
this.registerEmitter()
windowStage.loadContent('pages/Splash', (err, data) => {
if (err.code) {
return;
}
});
}
registerEmitter() {
emitter.on({
eventId : CommonData.EVENT_WINDOW_PORTRAIT_ID
}, () => {
if (!this.mWindow) {
return
}
this.mWindow.setPreferredOrientation(window.Orientation.PORTRAIT)
})
emitter.on({
eventId : CommonData.EVENT_WINDOW_LANDSCAPE_ID
}, () => {
if (!this.mWindow) {
return
}
this.mWindow.setPreferredOrientation(window.Orientation.LANDSCAPE)
})
}
unregisterEmitter() {
emitter.off(CommonData.EVENT_WINDOW_PORTRAIT_ID)
emitter.off(CommonData.EVENT_WINDOW_LANDSCAPE_ID)
}
}
由于視頻播放頁面和全屏播放頁面與EntryAbility無直接聯系,如果在操作頁面時修改窗口方向呢?我相信你也注意到了上面的代碼中使用到了@ohos.events.emitter,?emitter提供了在同一進程不同線程之間或者同一進程同一線程內,發送和處理事件的能力,可以通過訂閱事件、取消訂閱、發送事件等接口實現消息線程通信。所以我們在EntryAbility的onWindowStageCreate()接口回調時訂閱了橫豎屏切換事件,當然在應用退出時,也就是在onDestroy()接口被回調時,應該注取消訂閱,防止內存泄漏,消息錯亂。
發送橫豎屏切換事件:- 播放頁面切換到全屏播放時界面切換成橫屏,需要在FullScreen.ets界面被啟動回調aboutToAppear()接口時發送橫屏事件,通知Window修改方向。FullScreen.ets中的核對代碼:
aboutToAppear() {
// 橫屏顯示
emitter.emit({
eventId: CommonData.EVENT_WINDOW_LANDSCAPE_ID
})
}
- 全屏播放返回到視頻播放頁時需要將橫屏切換到豎屏顯示,所以當Playback.ets頁面的onPageShow()接口被觸發時,就發送豎屏事件,通知Window修改方向。Playback.ets中的核心代碼:
onPageShow() {
// 豎屏顯示
emitter.emit({
eventId: CommonData.EVENT_WINDOW_PORTRAIT_ID
})
}
這樣就完成了視頻播放頁面為豎屏,全屏播放為橫屏的功能。
3、播放時間同步
播放時間同步主要在視頻播放頁面與全屏播放頁面相互切換時使用,在兩個頁面切換時,除了時間同步外,播放狀態也需要同步。時間同步是指:視頻播放頁面在播放視頻時,假設播放到5s這個時間幀節點時,切換到全屏播放頁面,全屏播放進入播放狀態,且從5s這個時間幀節點開始播放。
如上所述,兩個頁面之間必須同步播放時間戳,頁面切換通過路由器@ohos. router 實現,在router.pushUrl()函數中可以添加參數,我們將時間戳通過自定義參數傳遞到目標界面,頁面返回到上一級頁面時,一般使用router.back(),此時通過發送事件同步消息實現視頻播放時間同步。具體實現請參看FullScreen.ets、Playback.ets、VideoView.ets三個類。
這個就是全屏播放頁面的實現,到目前已經將視頻播放器的所有頁面實現講述完畢。
??想了解更多關于開源的內容,請訪問:??
??51CTO 開源基礎軟件社區??
??https://ost.51cto.com??