
探秘鸿蒙 HarmonyOS NEXT:沉浸式页面开发实战攻略 原创
概述
本文章基于HarmonyOS NEXT操作系统,API12以上的版本。
沉浸式开发模式,旨在让应用界面高度聚焦于内容呈现,最大程度避免用户受到无关元素的干扰。在移动端应用里,全屏窗口由状态栏、应用界面和导航栏构成。在进行沉浸式页面开发时,通常会采用将应用页面拓展至状态栏和导航栏区域的方式,以此实现以下目标:
- 使页面和避让区域的色调统一,为用户提供更好的视觉体验。
- 最大程度利用屏幕可视区域,使页面获得更大的布局空间。
- 提供完全沉浸的体验,让用户沉浸其中,不被其他事物所干扰。
本文将介绍沉浸式页面的实现方案、原理以及提供以下常见沉浸式页面开发场景下一些适配问题的解决方案。
- [顶部或底部背景延伸场景]
- [顶部图片延伸场景]
- [滚动列表底部延伸场景]
- [全屏沉浸式场景]
- [深色背景下状态栏颜色适配场景]
实现原理
针对上面的设计要求,可以通过如下两种方式实现应用沉浸式效果:
-
[窗口全屏布局方案]:调整布局系统为全屏布局,界面元素延伸到状态栏和导航条区域实现沉浸式效果。当不隐藏避让区时,可通过接口查询状态栏和导航条区域进行可交互元素避让处理,并设置状态栏或导航条的颜色等属性与界面元素匹配。当隐藏避让区时,通过对应接口设置全屏布局即可。
-
[组件安全区方案]:布局系统保持安全区内布局,然后通过接口延伸绘制内容(如背景色,背景图)到状态栏和导航条区域实现沉浸式效果。
如何区分或使用?
组件安全区该方案下,界面元素仅做绘制延伸,无法单独布局到状态栏和导航条区域,针对需要单独布局UI元素到状态栏和导航条区域的场景建议使用窗口全屏布局方案处理。
关键技术
方案一:使用 Window.setWindowLayoutFullScreen() 方法设置窗口为全屏模式。
这种方案一般适用于一级界面Index中,要根据需求,看布局中的UI元素是否需要避让状态栏和导航条,否则可能产生UI元素重叠等情况。
如果,对控件顶部设置padding(具体数值与状态栏高度一致),实现对状态栏的避让;对底部设置padding(具体数值与底部导航条区域高度一致),实现对底部导航条的避让。
如果,去掉顶部和底部的padding设置,即不避让状态栏和导航条,UI元素就会发生重叠。
代码如下:
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
// 1.获取应用主窗口。
let windowClass: window.Window | undefined = undefined;
windowStage.getMainWindow().then(windowClass => {
console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(windowClass));
// 2.设置窗口全屏,实现沉浸式效果。
windowClass.setWindowLayoutFullScreen(true).then(() => {
console.info('Succeeded in setting the window layout to full-screen mode.');
}).catch((e: BusinessError) => {
console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(e));
})
}).catch((err: BusinessError) => {
console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
})
// 3.为沉浸式窗口加载对应的目标页面。
windowStage.loadContent("pages/Index", (err) => {
if (err.code) {
console.error('Failed to load the content. Cause:' + JSON.stringify(err));
return;
}
console.info('Succeeded in loading the content.');
});
}
};
方案二:设置组件的 expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]) 属性,扩展组件的安全区域到状态栏和导航栏,从而实现沉浸式。
代码如下:
@Entry
@Component
struct Example {
build() {
Column() {
Row() {
Text('Top Row')
.fontSize(40)
.textAlign(TextAlign.Center)
.width('100%')
}
.backgroundColor('#F08080')
// 设置顶部绘制延伸到状态栏
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
Row() {
Text('ROW2')
.fontSize(40)
}
.backgroundColor(Color.Orange)
.padding(20)
Row() {
Text('ROW3')
.fontSize(40)
}
.backgroundColor(Color.Orange)
.padding(20)
Row() {
Text('ROW4')
.fontSize(40)
}
.backgroundColor(Color.Orange)
.padding(20)
Row() {
Text('ROW5')
.fontSize(40)
}
.backgroundColor(Color.Orange)
.padding(20)
Row() {
Text('Bottom Row')
.fontSize(40)
.textAlign(TextAlign.Center)
.width('100%')
}
.backgroundColor(Color.Orange)
// 设置底部绘制延伸到导航条
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Center)
.backgroundColor('#008000')
.justifyContent(FlexAlign.SpaceBetween)
}
}
场景分析
场景一 顶部或底部背景延伸场景
场景描述
页面背景需要延伸到状态栏和导航条区域,页面内容在安全区展示。
开发步骤
使用[expandSafeArea]属性扩展背景组件安全区域
给设置背景色的组件设置expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]),使背景色延伸到状态栏和导航条。由于[expandSafeArea]属性不影响子组件的布局,所以Tabs组件内的内容默认在安全区域布局,避让状态栏和导航条。
代码如下:
Tabs({ barPosition: BarPosition.End }) {
// ...
}
.backgroundColor('#F1F3F5')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
场景二 顶部图片延伸场景
场景描述
页面顶部的图片要延伸到状态栏中去,形成沉浸式效果。顶部的返回按钮等交互组件,要合理避让状态栏。
开发步骤
- 设置图片expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP]),扩展图片上方的安全区域。由于[expandSafeArea]属性不影响兄弟组件的布局,顶部的按钮区域默认避让状态栏。
- 设置Swiper组件的[clip]属性为false,不裁剪内部组件。在设置[expandSafeArea]属性的组件的父组件是滚动类容器时,需配合[clip]属性使用。
代码如下:
Swiper(this.swiperController) {
ForEach(BANNER_IMAGES, (image: Resource) => {
Image(image)
.width('100%')
.height('100%')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
}, (image: Resource) => JSON.stringify(image))
}
.clip(false)
场景三 滚动列表底部延伸场景
场景描述
在列表滚动场景中,滚动时内容可与导航条区域重合,滚动到底部时,底部内容需避让导航条。
开发步骤
- 设置列表组件ListexpandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM]),扩展列表底部到安全区域。此时List组件显示区域扩大,滚动时列表内容可在导航条区域显示。
List() {
// ...
}
.layoutWeight(1)
.scrollBar(BarState.Off)
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
- 将滚动到底部的提示添加在列表项末尾,由于设置[expandSafeArea]属性不影响子组件的布局,所以滚动到底部时提示文字默认会避让导航条。
ForEach(getFaqData(), (faq: Faq) => {
ListItem() {
this.FaqItem(faq)
}
}, (faq: Faq) => JSON.stringify(faq))
ListItem() {
Text($r('app.string.faq_list_all'))
.width('100%')
.textAlign(TextAlign.Center)
.opacity(0.6)
.padding({ top: 10, bottom: 10 })
}
场景四 全屏沉浸式场景
场景描述
在一些视频播放或启动页的沉浸式页面中,为了更好的观看或操作体验,往往需要隐藏状态栏和导航栏。
开发步骤
在页面显示或隐藏时,使用[Window.setWindowLayoutFullScreen()]方法设置窗口是否为全屏模式,使用[Window.setWindowSystemBarEnable()]方法设置状态栏和导航条显隐。
代码如下:
onShown() {
this.windowClass.setWindowLayoutFullScreen(true);
this.windowClass.setWindowSystemBarEnable([]);
}
onHidden() {
this.windowClass.setWindowLayoutFullScreen(false);
this.windowClass.setWindowSystemBarEnable(['status', 'navigation']);
}
build() {
NavDestination() {
Column() {
Video({ src: $rawfile('video.mp4') })
// ...
}
.height('100%')
.width('100%')
}
.hideTitleBar(true)
.onShown(() => this.onShown())
.onHidden(() => this.onHidden())
}
场景五 深色背景下状态栏颜色适配场景
场景描述
在某些将深色背景延伸到状态栏的沉浸式页面中,需要设置状态栏时间文字、信号图标、电量图标等内容为浅色进行适配,避免状态栏内容不清晰,以此提升用户的视觉体验。
开发步骤
- 设置背景图片组件expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]),扩展安全区域到状态栏和导航栏,实现沉浸式效果。
Image(this.getBackGroundImage())
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
- 在页面显示或隐藏时,使用[Window.setWindowSystemBarProperties()]方法设置状态栏内容的颜色。
onShown() {
this.windowClass.setWindowSystemBarProperties({
statusBarContentColor: '#FFFFFF'
});
}
onHidden() {
this.windowClass.setWindowSystemBarProperties({
statusBarContentColor: '#000000'
});
}
build() {
NavDestination() {
// ...
}
.hideTitleBar(true)
.onShown(() => this.onShown())
.onHidden(() => this.onHidden())
}
此次 HarmonyOS NEXT 沉浸式页面开发实践,只是探索的开端。未来,技术浪潮将不断奔涌,希望会有更多的开发者们能以此次经验为基石,在技术海洋中持续破浪前行,利用 HarmonyOS NEXT 的特性创造出更多震撼人心的作品,为鸿蒙世界添砖加瓦。
