xc+avplayer无缝切换的示例可以参考下:EntryAbility页面:import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { window } from '@kit.ArkUI'; import { AVPlayerDemo } from '../pages/AVPlayerDemo'; export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); } onDestroy(): void { hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); } onWindowStageCreate(windowStage: window.WindowStage): void { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); windowStage.loadContent('pages/XCAvplayer', (err) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; } AppStorage.setOrCreate('player', new AVPlayerDemo()); hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); }); } onWindowStageDestroy(): void { // Main window is destroyed, release UI related resources hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); } onForeground(): void { // Ability has brought to foreground hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); } onBackground(): void { // Ability has back to background hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); } }XCAvplayer页面:import { myVideoSourceDate, VideoSource } from './myVideoSourceDate'; import { VideoComponent } from './VideoComponent'; @Entry @Component struct XCAvplayer { private data: myVideoSourceDate = new myVideoSourceDate([]); @State isLayoutFullScreen : boolean = false; @State fangDaIndex : number = -1; aboutToAppear(): void { let list: VideoSource[] = [ new VideoSource('文案0', 'https://xxx.mp4') ]; console.log('myAppliction is Appear') this.data = new myVideoSourceDate(list); } build() { Scroll() { Column() { List() { LazyForEach(this.data, (item: VideoSource,index : number) => { ListItem() { VideoComponent({item : item, isLayoutFullScreen : this.isLayoutFullScreen, index : index , fangDaIndex : this.fangDaIndex}) .visibility(this.isLayoutFullScreen && this.fangDaIndex !== index ? Visibility.None : Visibility.Visible) } }, (item: string) => item) }.cachedCount(5).scrollBar(BarState.Off).edgeEffect(this.isLayoutFullScreen ? EdgeEffect.None : EdgeEffect.Spring) } } .edgeEffect(this.isLayoutFullScreen ? EdgeEffect.None : EdgeEffect.Spring) .width('100%') } }VideoComponent页面:import { AVPlayerDemo } from './AVPlayerDemo'; import { VideoSource } from './myVideoSourceDate'; import window from '@ohos.window'; import { BusinessError } from '@ohos.base'; import { router } from '@kit.ArkUI'; @Component export struct VideoComponent { @ObjectLink item: VideoSource; index: number = -1; @Link isLayoutFullScreen: boolean; @Link fangDaIndex: number; @State bkColor: Color = Color.Red mXComponentController: XComponentController = new XComponentController(); @State player_changed: boolean = false; // player: AVPlayerDemo = new AVPlayerDemo(); player: AVPlayerDemo = AppStorage.get('player') as AVPlayerDemo // 设置窗口方向 setR(orientation: number) { window.getLastWindow(getContext(this)).then((win) => { win.setPreferredOrientation(orientation).then((data) => { console.log('setWindowOrientation: ' + orientation + ' Succeeded. Data: ' + JSON.stringify(data)); }).catch((err: string) => { console.log('setWindowOrientation: Failed. Cause: ' + JSON.stringify(err)); }); }).catch((err: string) => { console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err)); }); } // 设置沉浸式窗口 setFullScreen(isLayoutFullScreen: boolean) { window.getLastWindow(getContext(this)).then((win) => { win.setWindowLayoutFullScreen(isLayoutFullScreen, (err: BusinessError) => { const errCode: number = err.code; if (errCode) { console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err)); return; } console.info('Succeeded in setting the window layout to full-screen mode.'); }); }).catch((err: string) => { console.log('setWindowOrientation: Failed to obtain the top window. Cause: ' + JSON.stringify(err)); }); } build() { // 通过显隐控制控制其他listItrem是否展示 Column() { Text(this.item.text) .visibility(this.isLayoutFullScreen === false ? Visibility.Visible : Visibility.None) Stack() { XComponent({ id: 'video_player_id', type: XComponentType.SURFACE, controller: this.mXComponentController }) .onLoad(() => { this.player.setSurfaceID(this.mXComponentController.getXComponentSurfaceId()); this.player_changed = !this.player_changed; this.player.avPlayerLiveDemo(0, this.item.url); }) Row() { Button(this.isLayoutFullScreen ? '退出全屏' : '点击全屏') .onClick(() => { this.fangDaIndex = this.index this.isLayoutFullScreen = !this.isLayoutFullScreen; this.setR(this.isLayoutFullScreen ? 4 : 1) this.setFullScreen(this.isLayoutFullScreen) }) .backgroundColor(this.bkColor) Button('跳转页面') .onClick(() => { this.player.pause(); router.pushUrl({ url: 'pages/PageSec' }) }) .backgroundColor(this.bkColor) } } .height(this.isLayoutFullScreen ? '100%' : 200) } .width('100%') } }PageSec页面:import { AVPlayerDemo } from './AVPlayerDemo' @Entry @Component struct PageSec { private surfaceId: string = ''; xComponentController: XComponentController = new XComponentController(); @State rect: SurfaceRect | null = null; player: AVPlayerDemo = AppStorage.get('player') as AVPlayerDemo; build() { Column() { XComponent({ id: 'xcomponent', type: XComponentType.SURFACE, controller: this.xComponentController }) .onLoad(() => { let surfaceRect: SurfaceRect = { offsetX: 0, offsetY: 0, surfaceWidth: 1200, surfaceHeight: 500 }; this.xComponentController.setXComponentSurfaceRect(surfaceRect); this.surfaceId = this.xComponentController.getXComponentSurfaceId() this.player.setSurfaceID(this.surfaceId); this.player.start(); }) } .width('100%') } }myVideoSourceDate页面:export class myVideoSourceDate implements IDataSource { videoList: VideoSource[] = []; constructor(videoList: VideoSource[]) { this.videoList = videoList; } totalCount(): number { return this.videoList.length; } getData(index: number): VideoSource { return this.videoList[index]; } registerDataChangeListener(listener: DataChangeListener): void { } unregisterDataChangeListener(listener: DataChangeListener): void { } } @Observed export class VideoSource { text ?: string; url ?: string; constructor(text ?: string,url?: string) { this.text = text; this.url = url; } } import media from '@ohos.multimedia.media'; import { BusinessError } from '@ohos.base'; export class AVPlayerDemo { private count: number = 0; private surfaceID: string = ''; private url: string = ''; private avPlayer: media.AVPlayer | undefined; // 注册avplayer回调函数。 setAVPlayerCallback() { // seek操作结果回调函数。 this.avPlayer?.on('seekDone', (seekDoneTime: number) => { console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`); }) // error回调监听函数,当avplayer在操作过程中出现错误时,调用reset接口触发重置流程。 this.avPlayer?.on('error', (err: BusinessError) => { console.error(`Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`); this.avPlayer?.reset(); }) // 状态机变化回调函数。 this.avPlayer?.on('stateChange', async (state: string, reason: media.StateChangeReason) => { switch (state) { case 'idle': console.info('AVPlayer state idle called.'); this.avPlayer?.release(); break; case 'initialized': console.info('AVPlayer state initialized called.'); if (this.avPlayer != null && this.avPlayer != undefined) { this.avPlayer.surfaceId = this.surfaceID; } this.avPlayer?.prepare(); break; case 'prepared': console.info('AVPlayer state prepared called.'); if (this.count === 0 || this.count === 1) { console.info('AVPlayer start to play.'); if (this.avPlayer != null && this.avPlayer != undefined) { this.avPlayer.surfaceId = this.surfaceID; } this.avPlayer?.play(); } break; case 'playing': console.info('AVPlayer state playing called.'); if (this.avPlayer != null && this.avPlayer != undefined) { this.avPlayer.surfaceId = this.surfaceID } this.avPlayer?.play(); break; case 'paused': console.info('AVPlayer state paused called.'); this.avPlayer?.pause(); break; case 'completed': console.info('AVPlayer state paused called.'); this.avPlayer?.stop(); break; case 'stopped': console.info('AVPlayer state stopped called.'); this.avPlayer?.reset(); break; case 'released': console.info('AVPlayer state released called.' + this.surfaceID); break; default: break; } }) } async avPlayerLiveDemo(count: number, url ?: string, avplayer ?: media.AVPlayer) { this.count = count; if (url != undefined) { this.url = url; } this.avPlayer = await media.createAVPlayer(); this.setAVPlayerCallback(); this.avPlayer.url = url; } destroy() { this.avPlayer?.stop() this.avPlayer?.release() this.avPlayer = undefined } setSurfaceID(surface_id: string) { console.log('setSurfaceID : ' + surface_id); this.surfaceID = surface_id; } getAvPlayer(): media.AVPlayer | undefined { return this.avPlayer; } getSurfaceID(): string { return this.surfaceID; } setUrl(url: string) { this.url = url; } getUrl(): string { return this.url } start() { this.avPlayer?.play() } pause() { this.avPlayer?.pause(); } }
xc+avplayer无缝切换的示例可以参考下:
EntryAbility页面:
XCAvplayer页面:
VideoComponent页面:
PageSec页面:
myVideoSourceDate页面: