ArkUI 学习之实现沉浸式三种方式
一、概述
在移动端开发中,安全区域是指页面的显示区域,默认不与系统设置的非安全区域比如状态栏、导航栏区域重叠,默认情况下开发者开发的界面都被布局在安全区域内。例如下图中
@Entry @Component struct Index { build() { Column() { Text('安全区域').fontSize(30) }.width('100%').height('100%').backgroundColor(Color.Orange).justifyContent(FlexAlign.Center) } }
此时的布局方式就是非沉浸式布局,布局避让状态栏与导航栏,组件不会与其重叠。
而沉浸式布局就是,布局不避让状态栏与导航栏,全屏铺满,此时组件可能产生与其重叠的情况。例如下图中
二、实现沉浸式布局的方案有三种
1. setWindowLayoutFullScreen方法实现沉浸式
鸿蒙提供了setWindowLayoutFullScreen方法来设置全屏。参数为true时表示全屏显示,false表示非全屏显示。
1️⃣ ability中设置setWindowLayoutFullScreen
在ability中通过getMainWindow可以获取主窗体,然后通过得到的window对象的setWindowLayoutFullScreen属性设置窗口的布局是否为全屏显示状态。如下代码:
onWindowStageCreate(windowStage: window.WindowStage): void { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); /** 设置全屏显示 */ windowStage.getMainWindow().then((window => { window.setWindowLayoutFullScreen(true) })) windowStage.loadContent('pages/Index', (err) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; } hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.'); }); }
效果如下:
!!!注意:但是这种方式会给所有的页面都设置了沉浸式。
如果某些页面不需要设置沉浸式,还需要在页面中通过获取window来关闭:
import { window } from '@kit.ArkUI' @Entry @Component struct Index { /** 生命周期函数 */ aboutToAppear(): void { window.getLastWindow(getContext()).then((window) => { window.setWindowLayoutFullScreen(false) }) } build() { Column() { Text('安全区域').fontSize(30) }.width('100%').height('100%').backgroundColor(Color.Orange).justifyContent(FlexAlign.Center) } }
所以不推荐使用这种方式来设置沉浸式。
2️⃣ 页面中设置setWindowLayoutFullScreen
我们只需要某个页面全屏显示,这时候我们可以单独给这个页面设置setWindowLayoutFullScreen属性:
import { window } from '@kit.ArkUI' @Entry @Component struct Index { /** 生命周期函数 */ aboutToAppear(): void { window.getLastWindow(getContext()).then((window) => { window.setWindowLayoutFullScreen(true) }) } build() { Column() { Text('安全区域').fontSize(30) }.width('100%').height('100%').backgroundColor(Color.Orange).justifyContent(FlexAlign.Center) } }
2. 设置背景色统一实现沉浸式
如果我们只需要背景统一,实现状态栏-导航栏-主内容区的颜色统一,可以通过设置整体窗口的背景色来实现视觉沉浸式。
onWindowStageCreate(windowStage: window.WindowStage) { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); windowStage.loadContent('pages/Index', (err, data) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); return; } /** 设置背景色实现沉浸式 */ windowStage.getMainWindowSync().setWindowBackgroundColor("#9F6BF5") hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); });
!!!注意:效果在真机或者模拟器下才能显现效果,previewer 不能看到效果
3. expandSafeArea属性实现沉浸式
相对于通过setWindowLayoutFullScreen设置所有页面进行全局的设置,expandSafeArea是个按需的方式,哪个页面需要使用沉浸式,直接自己设置即可。
🐡 默认新建项目预览效果:
🐡 通过设置expandSafeArea属性后的效果:
expandSafeArea(types?: Array<SafeAreaType>, edges?: Array<SafeAreaEdge>)
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
types | Array <SafeAreaType> | 否 |
非必填,配置扩展安全区域的类型。未添加metadata配置项时,页面不避让挖孔, CUTOUT类型不生效。 默认值: [SafeAreaType.SYSTEM, SafeAreaType.CUTOUT, SafeAreaType.KEYBOARD] |
edges | Array <SafeAreaEdge> | 否 |
非必填,配置扩展安全区域的方向。 [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM, SafeAreaEdge.START, SafeAreaEdge.END] 扩展至所有非安全区域。 |
使用:
-
设置expandSafeArea背景色沉浸
🐡 对父容器设置才是背景色沉浸
@Entry @Component struct Index { build() { Column() { Text('设置 “背景色” 沉浸式') .fontSize(50) .fontColor(Color.Red) } .expandSafeArea() //设置沉浸式 .backgroundColor(Color.Orange) .height('100%') .width('100%') } }
🐡 如果对Text设置会连带文字一起沉浸到状态栏
@Entry @Component struct Index { build() { Column() { Text('设置 “背景色” 沉浸式') .fontSize(50) .fontColor(Color.Red).expandSafeArea()//设置沉浸式 } .expandSafeArea() //设置沉浸式 .backgroundColor(Color.Orange) .height('100%') .width('100%') } }
- 设置expandSafeArea图片沉浸
🐡 未设置沉浸式
@Entry @Component struct Index { build() { Stack() { Image($r('app.media.SplashScreen')) Text('设置 “图片” 沉浸式') .fontSize(50) .fontColor(Color.Red) }.width('100%').height('100%') } }
🐡 设置沉浸式
@Entry @Component struct Index { build() { Stack() { Image($r('app.media.SplashScreen')).expandSafeArea() Text('设置 “图片” 沉浸式') .fontSize(50) .fontColor(Color.Red) }.width('100%').height('100%') } }
-
多层组件也能设置expandSafeArea沉浸,只要父组件没有限制其到状态栏
@Entry @Component struct Index { build() { Stack({ alignContent: Alignment.TopStart }) { this.LayoutBuilder() Text('设置 多层组件 沉浸式') .fontSize(50) .fontColor(Color.White) }.width('100%').height('100%') } @Builder LayoutBuilder() { Column() { Image($r('app.media.SplashScreen')).expandSafeArea() //设置沉浸式 } } }
-
多个组件也能设置expandSafeArea沉浸
@Entry @Component struct Index { build() { Stack({ alignContent: Alignment.TopStart }) { this.LayoutBuilder() Text('设置 expandSafeArea 沉浸式') .fontSize(50) .fontColor(Color.White) .expandSafeArea() //设置沉浸式1 } .height('100%') .width('100%') } @Builder LayoutBuilder() { Column() { Image($r('app.media.SplashScreen')).expandSafeArea() //设置沉浸式2 } } }
说明:
1. expandSafeArea设置沉浸式更灵活,可以根据情况对其中一个或多个组件设置沉浸式
2. expandSafeArea设置沉浸式不会导致页面上下抖动
3. 安全区域不会限制内部组件的布局和大小,不会裁剪内部组件。
4. 设置expandSafeArea()时,不传参,走默认值处理;设置expandSafeArea([],[])时,相当于入参是空数组,此时设置expandSafeArea属性不生效。
5. 组件设置expandSafeArea之后生效的条件为:1. type为SafeAreaType.KEYBOARD时默认生效,组件不避让键盘。 2. 设置其他type,组件的边界与安全区域重合时组件能够延伸到安全区域下。
6. 组件延伸到安全区域下,在安全区域处的事件,如点击事件等可能会被系统拦截,优先给状态栏等系统组件响应。