/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import window from '@ohos.window';
import { promptAction } from '@kit.ArkUI';
import { FlowItemContentData } from '../data/FlowItemContent';
import { FlowItemContent, FlowItemContentsData } from '../model/BasicDataSource';
import { XVideoComponent } from './XComponentVideo';
import { DynamicsRouter } from 'routermodule';
import { PlatformInfo, PlatformTypeEnum } from 'utils';
// window.setWindowSystemBarEnable方法的预设值,设置窗口全屏模式时状态栏和导航栏是否显示
const WINDOW_SYSTEM_BAR: Array<'status' | 'navigation'> = ['navigation', 'status'];
const ASPECT_RATIO: number = 1.77777778; //元素宽高比
const VIDEO_Z_INDEX: number = 30; // 组件zIndex
/**
* 功能描述: 本示例介绍了使用@ohos.multimedia.media接口和@ohos.window接口配合XComponent组件实现媒体全屏的功能。
*
* 推荐场景: 多用于首页瀑布流媒体播放等场景
*
* 核心组件:
* 1. window
* 2. XComponent
*
* 实现步骤:
* 1. 在自定义组件XVideoComponent内调用changeOrientation方法,实现媒体全屏效果。
* 2. 调用@ohos.window的getLastWindow方法获取当前应用内最上层的子窗口,若无应用子窗口,则返回应用主窗口。
* 3. 利用获取到的窗口对象,调用setWindowSystemBarEnable方法设置窗口是否显示导航栏和状态栏。
* 4. 调用窗口对象的setPreferredOrientation方法设置窗口旋转方向和重力感应。
* 5. 调用窗口对象的setWindowLayoutFullScreen方法实现沉浸式布局。
*/
@Component
export struct MediaFullScreenComponent {
@State maskShow: boolean = false; // 遮罩层是否显示
@State isLandscape: boolean = false; // 是否横屏状态
@State cachedCountNumber: number = 6; // 懒加载缓存数
@State contentData: FlowItemContentsData = new FlowItemContentsData(); // 瀑布流内容
@State selectedVideo: string = ''; // 选择的视频名称
@Provide pageMediaFullScreen: NavPathStack = new NavPathStack();
@State videoLocation: Area = {
// 视频在屏幕中的位置信息
width: 0,
height: 0,
position: { x: 0, y: 0 },
globalPosition: { x: 0, y: 0 }
};
popPage: (() => void) | undefined = undefined;
async aboutToAppear() {
this.contentData.pushData(FlowItemContentData);
}
async aboutToDisappear() {
// 销毁组件时恢复window方向
const currentWindow = await window.getLastWindow(getContext(this));
currentWindow.setWindowSystemBarEnable(WINDOW_SYSTEM_BAR);
}
@Builder
videoArea() {
// 性能知识点: 功能是以har的形式集成在主工程中,没有@Entry修饰的组件,无法使用@Entry组件的onBackPress生命周期函数。
NavDestination() {
Column() {
// 引入自定义视频组件
XVideoComponent({
fileName: this.selectedVideo,
videoLocation: this.videoLocation,
isLandscape: this.isLandscape,
maskShow: this.maskShow
})
Column() {
}
.width($r('app.string.media_full_screen_layout_100'))
.height($r('app.string.media_full_screen_layout_100'))
.backgroundColor(Color.Transparent)
.position({ x: 0, y: 0 })
.zIndex(VIDEO_Z_INDEX)
.visibility(this.maskShow ? Visibility.Visible : Visibility.None)
WaterFlow() {
// 性能知识点: LazyForEach 懒加载优化,详情请见 https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/performance/lazyforeach_optimization.md/
LazyForEach(this.contentData, (moment: FlowItemContent, index: number) => {
FlowItem() {
ReusableComponent({
index,
moment,
selectedVideo: this.selectedVideo,
videoLocation: this.videoLocation,
maskShow: this.maskShow
})
}
.width($r('app.string.media_full_screen_video_width'))
}, (moment: FlowItemContent) => moment.id)
}
.columnsTemplate('1fr 1fr')
.columnsGap($r('app.integer.media_full_screen_main_page_row_padding_left'))
.rowsGap($r('app.integer.media_full_screen_main_page_row_padding_left'))
.cachedCount(this.cachedCountNumber) // 懒加载缓存配置
.width($r('app.string.media_full_screen_layout_100'))
.height($r('app.string.media_full_screen_layout_100'))
.clip(false)
}
.backgroundColor($r('app.color.media_full_screen_search_border_color'))
.height($r('app.string.media_full_screen_layout_100'))
.layoutWeight(1)
.clip(true)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
}
.hideTitleBar(true)
// TODO:知识点:返回时进行判断,如果在非全屏状态则返回首页,否则仅退出全屏
.onBackPressed(() => {
if (this.selectedVideo === '') {
if (this.popPage) {
this.popPage();
} else {
// 未传入返回接口时给出弹框提示
promptAction.showToast({
message: $r('app.string.media_full_screen_back_error_message'),
duration: 1000
})
}
return true;
} else {
this.maskShow = false;
this.isLandscape = !this.isLandscape;
return true;
}
})
}
build() {
// 应用主页用NavDestination承载,用于显示Navigation的内容区
Navigation(this.pageMediaFullScreen) {
}
.mode(NavigationMode.Stack)
.onAppear(() => {
this.pageMediaFullScreen.pushPathByName("MediaFullScreen", null, false);
})
// 创建NavDestination组件,需使用此组件的onBackPressed回调拦截返回事件
.navDestination(this.videoArea)
.gesture(
SwipeGesture({ direction: SwipeDirection.Horizontal })
.onAction((event: GestureEvent) => {
if (PlatformInfo.getPlatform() === PlatformTypeEnum.IOS) {
if (event) {
DynamicsRouter.popAppRouter();
}
}
})
)
}
}
// 性能知识点: @Reusable复用组件优化,详情请见 https://docs.openharmony.cn/pages/v4.0/zh-cn/application-dev/performance/component-recycle.md/
@Reusable
@Component
struct ReusableComponent {
@Prop index: number;
@Prop moment: FlowItemContent;
@Link selectedVideo: string;
@Link videoLocation: Area;
@Link maskShow: boolean;
build() {
Column() {
Stack({ alignContent: Alignment.Center }) {
Image($r(`app.media.${this.moment.mediaPreview}`))
.width('100%')
.aspectRatio(ASPECT_RATIO)
Image($r("app.media.media_full_screen_play"))
.width($r('app.integer.media_full_screen_main_page_icon_play_width'))
.height($r('app.integer.media_full_screen_main_page_icon_play_height'))
}
.id(`mediaPic${this.index}`)
.onClick((event?: ClickEvent) => {
if (this.selectedVideo !== '') {
return;
}
this.maskShow = true;
this.selectedVideo = this.moment.media; // 将选中视频名称赋值给@Link selectedVideo,以便传到自定义组件XVideoComponent内
if (event) {
this.videoLocation = event.target.area; // 将选中视频位置信息赋值给@Link videoLocation,以便传到自定义组件XVideoComponent内
}
})
Text(this.moment.text)
.lineHeight($r('app.integer.media_full_screen_main_page_useName_line_height'))
.fontFamily($r('app.string.media_full_screen_harmony_hei_ti'))
.fontWeight(FontWeight.Medium)
.fontSize($r('app.integer.media_full_screen_main_page_userText_fontSize'))
.fontColor($r('app.color.media_full_screen_title_font_color'))
.padding($r('app.integer.media_full_screen_main_page_row_padding_left'))
Row() {
Image($r(`app.media.${this.moment.user.userImage}`))
.autoResize(false)
.width($r('app.integer.media_full_screen_main_page_user_image_width'))
.height($r('app.integer.media_full_screen_main_page_user_image_height'))
.borderRadius($r('app.integer.media_full_screen_main_page_user_image_border_radius'))
Text(this.moment.user.userName)
.fontSize($r('app.integer.media_full_screen_main_page_useName_fontSize'))
.fontColor($r('app.color.media_full_screen_title_font_color'))
.lineHeight($r('app.integer.media_full_screen_main_page_userText_line_height'))
.fontFamily($r('app.string.media_full_screen_harmony_hei_ti'))
.margin({ left: $r('app.integer.media_full_screen_main_page_user_col_margin_left') })
.layoutWeight(1)
}
.padding({
left: $r('app.integer.media_full_screen_main_page_row_padding_left'),
right: $r('app.integer.media_full_screen_main_page_row_padding_right'),
top: $r('app.integer.media_full_screen_main_page_row_padding_top'),
bottom: $r('app.integer.media_full_screen_main_page_row_padding_bottom')
})
}
.shadow({ radius: $r('app.integer.media_full_screen_stack_shadow_radius'), color: Color.Gray })
.border({ radius: $r('app.integer.media_full_screen_main_page_row_padding_left') })
.backgroundColor(Color.White)
.alignItems(HorizontalAlign.Start)
}
}