immersion-mode.md 7.7 KB
Newer Older
1
# 沉浸式界面开发
D
duangavin123 已提交
2 3 4 5 6 7 8 9 10

## 场景说明
沉浸式界面通常是指全屏显示,即当前画面占据整个屏幕。画面放大的同时,让用户摆脱无关信息的干扰,带给用户沉浸式的体验。常见的场景有:视频播放、游戏等。本例即为大家介绍如何开发沉浸式界面。

## 效果呈现
本例中的沉浸式界面有三种实现方式,对应效果如下:

| 方案一:颜色背景铺满                | 方案二:图片背景铺满                          | 方案三:背景铺满的同时、状态栏不可见  |
| ----------------------------------- | --------------------------------------------- | ------------------------------------- |
11
| ![fullcolor](figures/fullcolor.PNG) | ![fullbackground](figures/fullbackground.PNG) | ![fullscreen](figures/fullscreen.PNG) |
D
duangavin123 已提交
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26


## 运行环境
本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:

- IDE: DevEco Studio 3.1 Beta2
- SDK: Ohos_sdk_public 3.2.11.9(API Version 9 Release)

## 实现思路
如果一个应用想要获得沉浸式的体验,开发者可以通过以下三种方式进行实现:

- 颜色背景通铺:使应用页面的背景色和状态栏、导航栏的背景色一致。可通过setWindowSystemBarProperties进行设置。
- 图片背景通铺:将状态栏、导航栏的背景色设置为透明以便呈现应用界面的背景,同时通过 windowClass.on接口获取到状态栏、导航栏的区域信息,进行规避处理,以免状态栏、导航栏的内容遮挡住应用内容。
- 隐藏导航栏和状态栏:使用setWindowSystemBarEnable设置导航栏和状态栏为隐藏状态。

27 28
> ![icon-note.gif](../device-dev/public_sys-resources/icon-note.gif) **说明:**
> 沉浸式的设置最好放在ability的onWindowStageCreate的生命周期里,此时刚好可以获取窗口的信息,放在页面页面生命周期里会出现窗口大小不一致,影响体验。
D
duangavin123 已提交
29 30 31

下文将分别介绍这三种方案的具体开发步骤。

32

D
duangavin123 已提交
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
## 开发步骤
### 颜色背景通铺
此方案通过调用setWindowSystemBarProperties接口将状态栏和导航栏的背景色设置为跟应用窗口相同的颜色,以达到界面全屏的效果。

具体代码如下:

```ts
import window from '@ohos.window';
import common from '@ohos.app.ability.common';
 
@Entry
@Component
struct Type2 {
  @State message: string = 'Hello World'
  // 获取UIAbility上下文
  context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext
  async setSystemBar() {
    // 获取当前应用窗口
    let windowClass:window.Window = await window.getLastWindow(context)
    // 将状态栏和导航栏的背景色设置为跟应用窗口相同的颜色
    await windowClass.setWindowSystemBarProperties({
      navigationBarColor: "#00FF00",
      statusBarColor: "#00FF00",
      navigationBarContentColor: "#00FF00",
      statusBarContentColor: "#00FF00"
    })
  }
 
  aboutToAppear() {
    this.setSystemBar()
  }
 
  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}
```
78
此方案的优势在于不需要处理应用窗口和状态栏、导航栏窗口的遮挡关系,因为此方案没有使用setWindowLayoutFullScreen 接口设置沉浸式布局,所以三个窗口是平铺的,不会重叠。劣势在于无法将应用的背景图等信息延伸到状态栏、导航栏窗口中。适用于扁平化设计风格的应用。
D
duangavin123 已提交
79 80 81 82 83 84 85 86 87 88 89 90 91

### 图片背景通铺
这种方案可以实现图片背景的通铺,同时又能避免状态栏和导航栏的内容跟应用内容相互遮挡,导致显示效果异常。
为了能让应用的有效显示范围避开系统的状态栏和导航栏,以免内容重叠,我们可以通过windowClass.on(type: ‘avoidAreaChange’, callback: Callback<{AvoidAreaType, AvoidArea}>) 获取系统规避区域的大小,并对这一块区域做出相应的规避。
其中回调参数AvoidArea是规避区域,可以通过其获取规避区域的具体范围;AvoidAreaType是规避区域的类型其取值如下,示例中需要规避的状态栏和导航栏属于TYPE_SYSTEM类型。

| 名称                  | 值   | 说明               |
| -------------------- | ---- | ----------------- |
| TYPE_SYSTEM           | 0    | 表示系统默认区域。 |
| TYPE_CUTOUT           | 1    | 表示刘海屏区域。   |
| TYPE_SYSTEM_GESTURE9+ | 2    | 表示手势区域。     |
| TYPE_KEYBOARD9+       | 3    | 表示软键盘区域     |
具体代码如下:
92

D
duangavin123 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
**page代码**

```ts
// index.ets
@Entry
@Component
struct Type3 {
  @State message: string = 'Hello World'
  @StorageLink("topHeight") topHeight: number = 0
  @StorageLink("bottomHeight") bottomHeight: number = 0
 
  build() {
    Column() {
      // 在界面顶部放置一个Row组件,用于占位
      Row() {
 
      }
      .width("100%")
      // 设置Row组件的高度为状态栏的高度,可避免界面内容与状态栏内容重叠
      .height(px2vp(this.topHeight))
      Row() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .position({ x: 0, y: 0 })
      }
      .width("100%")
      .flexGrow(1)
      // 在界面底部放置一个Row组件,用于占位
      Row() {
 
      }
      .width("100%")
      // 设置Row组件的高度为导航栏的高度,可避免界面内容与导航栏内容重叠
      .height(px2vp(this.bottomHeight))
    }
    .backgroundImage($r("app.media.icon"))
    .backgroundImageSize(ImageSize.Cover)
    .width("100%")
    .height("100%")
  }
}
```
**ability代码**
```ts
// MainAbility.ts
import window from '@ohos.window';

async function enterImmersion(windowClass: window.Window) {
    // 获取状态栏和导航栏的高度
    windowClass.on("avoidAreaChange", ({ type, area }) => {
        if (type == window.AvoidAreaType.TYPE_SYSTEM) {
            // 将状态栏和导航栏的高度保存在AppStorage中
            AppStorage.SetOrCreate<number>("topHeight", area.topRect.height);
            AppStorage.SetOrCreate<number>("bottomHeight", area.bottomRect.height);
        }
    })
    // 设置窗口布局为沉浸式布局
    await windowClass.setWindowLayoutFullScreen(true)
    await windowClass.setWindowSystemBarEnable(["status", "navigation"])
    // 设置状态栏和导航栏的背景为透明
    await windowClass.setWindowSystemBarProperties({
        navigationBarColor: "#00000000",
        statusBarColor: "#00000000",
        navigationBarContentColor: "#FF0000",
        statusBarContentColor: "#FF0000"
    })
}

export default class MainAbility extends Ability {
  ...
  async onWindowStageCreate(windowStage: window.WindowStage) {
    let windowClass:window.Window = await windowStage.getMainWindow()
    await enterImmersion(windowClass)
    windowStage.loadContent('pages/page5')
  }
  ...
}
```
### 隐藏状态栏、导航栏
隐藏状态栏、导航栏可以达到完全沉浸的效果,使用setWindowSystemBarEnable接口即可实现。

具体代码如下:

```ts
import window from '@ohos.window';
import common from '@ohos.app.ability.common';

@Entry
@Component
struct Type3 {
  @State message: string = 'Hello World'
  context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext
  async setSystemBar() {
	let windowClass = await window.getLastWindow(context)
	//设置导航栏,状态栏不可见
	await windowClass.setWindowSystemBarEnable([])
  }

  aboutToAppear() {
	this.setSystemBar()
  }

  build() {
	Row() {
	  Column() {
		Text(this.message)
		  .fontSize(50)
		  .fontWeight(FontWeight.Bold)
	  }
	  .width('100%')
	}
	.backgroundColor("#ffee33")
	.height('100%')
  }
}
```

## 参考
[窗口](../application-dev/reference/apis/js-apis-window.md)