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. 组件延伸到安全区域下,在安全区域处的事件,如点击事件等可能会被系统拦截,优先给状态栏等系统组件响应。

posted on 2024-10-24 13:46  梁飞宇  阅读(413)  评论(0)    收藏  举报