• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 窗口管理开发常见问题
2<!--Kit: ArkUI-->
3<!--Subsystem: Window-->
4<!--Owner: @oh_wangxk; @logn-->
5<!--Designer: @hejunfei1991-->
6<!--Tester: @qinliwen0417-->
7<!--Adviser: @ge-yafang-->
8
9## 如何获取状态栏和导航栏高度(API 9)
10
11**解决措施**
12
13在加载窗口内容之前,采用systemAvoidAreaChange事件监听。
14
15**代码示例**
16
17```
18// MainAbility.ts
19import window from '@ohos.window';
20
21/**
22 * 设置沉浸式窗口,并获取状态栏和导航栏高度
23 * @param mainWindow 主窗口对象
24 */
25async function enterImmersion(mainWindow: window.Window) {
26  window.on("systemBarTintChange", (data) => {
27    let avoidAreaRect = data.regionTint[0].region; //data.regionTint是个数组,包含状态栏、导航栏的矩形区域坐标。
28  })
29  await mainWindow.setFullScreen(true)
30  await mainWindow.setSystemBarEnable(["status", "navigation"])
31  await mainWindow.systemBarProperties({
32    navigationBarColor: "#00000000",
33    statusBarColor: "#00000000",
34    navigationBarContentColor: "#FF0000",
35    statusBarContentColor: "#FF0000"
36  })
37}
38export default class MainAbility extends Ability {
39  // do something
40  async onWindowStageCreate(windowStage: window.WindowStage) {
41    let mainWindow = await windowStage.getMainWindow()
42    await enterImmersion(mainWindow)
43    windowStage.loadContent('pages/index')
44  }
45  // do something
46}
47```
48
49
50## 应用如何设置隐藏顶部的状态栏(API 9)
51
52**解决措施**
53
54在UIAbility的onWindowStageCreate的生命周期中设置setWindowSystemBarEnable接口即可。
55
56**代码示例**
57
58```
59onWindowStageCreate(windowStage){
60  windowStage.getMainWindowSync().setWindowSystemBarEnable([])
61  ......
62}
63```
64
65**参考链接**
66
67[窗口基础能力文档](../reference/apis-arkui/arkts-apis-window-Window.md)
68
69## 如何锁定设备竖屏,使得窗口不随屏幕旋转(API 9)
70
71适用于Stage模型。
72
73**解决措施**
74
75采用窗口的setPreferredOrientation方法可以实现该效果,将orientation参数设置为window.Orientation.PORTRAIT时,可锁定屏幕为竖屏。
76
77**代码示例**
78
79```
80import window from "@ohos.window";
81//1.获取窗口实例对象,新建窗口使用createWindow方法,获取已有的窗口使用findWindow方法
82let windowClass = null;
83let config = {name: "alertWindow", windowType: window.WindowType.TYPE_SYSTEM_ALERT, ctx: this.context};
84try {
85    let promise = window.createWindow(config);
86    promise.then((data)=> {
87        windowClass = data;
88        console.info('Succeeded in creating the window. Data:' + JSON.stringify(data));
89    }).catch((err)=>{
90        console.error('Failed to create the Window. Cause:' + JSON.stringify(err));
91    });} catch (exception) {
92    console.error('Failed to create the window. Cause: ' + JSON.stringify(exception));
93}
94//2.窗口实例使用setPreferredOrientation方法,设置窗口的显示方向,PORTRAIT为固定竖屏,其他方向可参照参考链接
95let orientation = window.Orientation.PORTRAIT;
96if (windowClass) {
97    windowClass.setPreferredOrientation(orientation, (err) => {
98        if (err.code) {
99            console.error('Failed to set window orientation. Cause: ' + JSON.stringify(err));
100            return;
101        }
102        console.info('Succeeded in setting window orientation.');
103}
104```
105
106**参考链接**
107
108[window.Orientation](../reference/apis-arkui/arkts-apis-window-e.md#orientation9)
109
110## 调用Window实例的setWindowSystemBarProperties接口设置窗口状态栏和导航栏的高亮属性时不生效(API 9)
111
112适用于Stage模型。
113
114**解决措施**
115
116状态栏字体高亮属性的本质就只是让字体变成白色。调用window实例的setWindowSystemBarProperties接口时,如果设置了状态栏内容颜色statusBarContentColor,就以开发者设置的颜色为准,isStatusBarLightIcon状态栏字体高亮属性就不生效;同理,如果设置了导航栏内容颜色navigationBarContentColor,isNavigationBarLightIcon导航栏字体高亮属性就不生效。
117
118**参考链接**
119
120[window.SystemBarProperties](../reference/apis-arkui/arkts-apis-window-i.md#systembarproperties)
121
122
123## 如何保持屏幕常亮(API 9)
124
125**解决措施**
126
127设置屏幕常亮,不熄屏。
128
129获取窗口实例对象后,调用[setWindowKeepScreenOn方法](../reference/apis-arkui/arkts-apis-window-Window.md#setwindowkeepscreenon9)可设置屏幕是否常亮。
130
131**代码示例**
132
133```
134let isKeepScreenOn = true;
135try {
136    windowClass.setWindowKeepScreenOn(isKeepScreenOn, (err) => {
137        if (err.code) {
138            console.error('Failed to set the screen to be always on. Cause: ' + JSON.stringify(err));
139            return;
140        }
141        console.info('Succeeded in setting the screen to be always on.');
142    });
143} catch (exception) {
144    console.error('Failed to set the screen to be always on. Cause: ' + JSON.stringify(exception));
145}
146```
147
148
149## 如何监听窗口大小的变化(API 9)
150
151获取窗口实例对象后,可以通过[window.on('windowSizeChange')](../reference/apis-arkui/arkts-apis-window-Window.md#onwindowsizechange7)方法实现对窗口尺寸大小变化的监听。
152
153需要注意的是,在window侧如果窗口大小没发生变化,此监听不会被触发。如直接旋转180度的情况下,窗口大小并没有改变,此时不会通知回调。在这种情况下,应用可以通过监听[display.on('change')](../reference/apis-arkui/js-apis-display.md#displayonaddremovechange)事件,在callback中通过display接口来获取窗口尺寸大小。
154
155```
156try {
157    windowClass.on('windowSizeChange', (data) => {
158        console.info('Succeeded in enabling the listener for window size changes. Data: ' + JSON.stringify(data));
159   });
160} catch (exception) {
161    console.error('Failed to enable the listener for window size changes. Cause: ' + JSON.stringify(exception));
162}
163```
164
165## 如何监听当前屏幕的横竖屏状态(API 10)
166
167**解决措施**
168
169应用可以通过display.on监听屏幕状态改变。
170
171**参考链接**
172
173[开启显示设备变化的监听](../reference/apis-arkui/js-apis-display.md#displayonaddremovechange)
174
175## 如何实现页面跟随屏幕横竖屏自动旋转(API 10)
176
177**解决措施**
178
1791.Abilty级别配置:在模块配置文件module.json5中将EntryAbility设置为"orientation"。
1802.动态设置:使用window.setPreferredOrientation设置窗口方向。
181
182**代码示例**
183```ts
184import window from '@ohos.window';
185import display from '@ohos.display';
186
187const TAG = 'foo'
188const ORIENTATION: Array<string> = ['垂直', '水平', '反向垂直', '反向水平']
189
190@Entry
191@Component
192struct ScreenTest {
193  @State rotation: number = 0
194  @State message: string = ORIENTATION[this.rotation]
195
196  aboutToAppear() {
197    this.setOrientation()
198
199    let callback = async () => {
200      let d = display.getDefaultDisplaySync()
201      this.rotation = d.rotation
202      this.message = ORIENTATION[this.rotation]
203      console.info(TAG, JSON.stringify(d))
204    }
205    try {
206      display.on("change", callback); // 监听屏幕状态改变
207    } catch (exception) {
208      console.error(TAG, 'Failed to register callback. Code: ' + JSON.stringify(exception));
209    }
210  }
211
212  setOrientation() {
213    try {
214      window.getLastWindow(this.getUIContext().getHostContext(), (err, data) => { // 获取window实例
215        if (err.code) {
216          console.error(TAG, 'Failed to obtain the top window. Cause: ' + JSON.stringify(err));
217          return;
218        }
219        let windowClass = data;
220        console.info(TAG, 'Succeeded in obtaining the top window. Data: ' + JSON.stringify(data));
221
222        let orientation = window.Orientation.AUTO_ROTATION; // 设置窗口方向为传感器自动旋转模式。
223        try {
224          windowClass.setPreferredOrientation(orientation, (err) => {
225            if (err.code) {
226              console.error(TAG, 'Failed to set window orientation. Cause: ' + JSON.stringify(err));
227              return;
228            }
229            console.info(TAG, 'Succeeded in setting window orientation.');
230          });
231        } catch (exception) {
232          console.error(TAG, 'Failed to set window orientation. Cause: ' + JSON.stringify(exception));
233        }
234        ;
235      });
236    } catch (exception) {
237      console.error(TAG, 'Failed to obtain the top window. Cause: ' + JSON.stringify(exception));
238    }
239    ;
240  }
241
242  build() {
243    Row() {
244      Column() {
245        Text(`${this.rotation}`).fontSize(25)
246        Text(`${this.message}`).fontSize(25)
247      }
248      .width("100%")
249    }
250    .height("100%")
251  }
252}
253```
254**参考链接**
255
256[设置窗口的显示方向属性](../reference/apis-arkui/arkts-apis-window-Window.md#setpreferredorientation9)
257[开启显示设备变化的监听](../reference/apis-arkui/js-apis-display.md#displayonaddremovechange)
258
259## 在display.on('change')监听回调中,无法使用Window实例获取更新后的窗口大小(API 10)
260
261**解决措施**
262
263旋转涉及[@ohos.window](../reference/apis-arkui/arkts-apis-window.md)和[@ohos.display](../reference/apis-arkui/js-apis-display.md)两个模块,处于不同进程。由于旋转完后display的更新时间早于window的更新时间(display旋转时直接宽高互换,提前可预知;window要等ArkUI布局完成才能确定窗口大小,耗时长),故在display触发变化时获取窗口信息会存在时序问题(窗口信息还未更新完成,此时使用Window实例获取到的还是原来的宽高)。应用可以通过display.on('change')接口监听显示设备变化,在callback中通过Display实例获取屏幕的width、height、orientation等信息。
264
265**错误示例**
266
267```ts
268// display先更新
269display.on('change', async (data) => {
270  let newDisplay: display.Display = display.getDefaultDisplaySync();
271  console.info('Orientation: ' + newDisplay.orientation);
272  let windowClass: window.Window = await window.getLastWindow(this.context);
273  // window后更新,获取到的还是原来的宽高
274  let windowProperties = windowClass.getWindowProperties();
275  console.info('Width: ' + windowProperties.windowRect.width +
276    ', height: ' + windowProperties.windowRect.height);
277  // 请确保已获取到相关Window实例,即windowClass
278  windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_CUTOUT);
279});
280```
281
282**正确示例**
283
284```ts
285display.on('change', (data) => {
286  console.info(`Succeeded in enabling the listener for display changes. Data: ${data}`);
287  let newDisplay: display.Display = display.getDefaultDisplaySync();
288  console.info(`Orientation: ${newDisplay.orientation} , width: ${newDisplay.width} , height: ${newDisplay.height}`);
289});
290```
291
292**参考链接**
293
294[display.on('change')](../reference/apis-arkui/js-apis-display.md#displayonaddremovechange)
295
296## 如何同时获取屏幕方向orientation和系统规避区avoidAreaChange信息(API 10)
297
298可以通过[on('avoidAreaChange')](../reference/apis-arkui/arkts-apis-window-Window.md#onavoidareachange9)接口监听窗口系统规避区域的变化,在callback中获取avoidAreaChange信息,并通过Display实例获取屏幕方向orientation等信息。
299
300```ts
301// 请确保已获取到相关Window实例,即windowClass
302windowClass.on('avoidAreaChange', async (data) => {
303  console.info('Succeeded in enabling the listener for avoid area changes. Type: ' +
304    JSON.stringify(data.type) + ', area ' + JSON.stringify(data.area));
305  let newDisplay: display.Display = display.getDefaultDisplaySync();
306  console.info('Orientation: ' + newDisplay.orientation);
307  let windowClass: window.Window = await window.getLastWindow(this.context);
308  windowClass.getWindowAvoidArea(window.AvoidAreaType.TYPE_CUTOUT);
309});
310```
311
312## 在display.on('foldDisplayModeChange')监听回调中,使用display.getDefaultDisplaySync获取当前屏幕宽高错误(API10)
313
314**解决措施**
315
316对于强制横屏应用,在设备发生折叠开合动作时,会触发foldDisplayModeChange,此时Display里对应旋转属性还未更新,导致通过getDefaultDisplaySync获取到的宽高为设备竖屏的宽高。应用可以通过display.on('change')接口监听显示设备变化,在回调函数中通过Display实例获取屏幕的宽高等信息。
317
318**代码示例**
319
320```ts
321display.on('change', (data) => {
322  console.info('Succeeded in enabling the listener for display changes. Data: ' +
323  JSON.stringify(data));
324  let newDisplay: display.Display = display.getDefaultDisplaySync();
325  console.info('width: ' + newDisplay.width + ', height: ' + newDisplay.height);
326});
327```
328
329**参考链接**
330
331[display.on('change')](../reference/apis-arkui/js-apis-display.md#displayonaddremovechange)
332
333## 窗口Orientation枚举值8\~10或12和枚举值13\~16的区别(API9)
334
3351. 窗口设置8\~10或12,会跟随传感器自动旋转,且受控制中心的旋转开关控制。
3362. 窗口设置13\~16,会临时旋转到指定方向(如:13会临时旋转到竖屏),之后跟随传感器自动旋转,受控制中心的旋转开关控制,且可旋转方向受系统判定。
337
338两者的区别是,调用13\~16时会临时旋转到指定方向,且前后台切换时窗口方向保持,而调用8\~10或12前后台切换时窗口方向不会保持。
339
340**场景举例:**
3411. 竖持手机,关闭旋转锁定开关 -> 应用设置方向为AUTO_ROTATION_RESTRICTED -> 将手机旋转为横屏(**应用方向为横屏**) -> 应用退出后台进入桌面,竖持手机(方向为竖屏) -> 应用切换至前台(**应用方向为竖屏**)
3422. 竖持手机,关闭旋转锁定开关 -> 应用设置方向为USER_ROTATION_PORTRAIT(**应用方向为竖屏**) -> 将手机旋转为横屏(**应用方向为横屏**) -> 应用退出后台进入桌面,竖持手机(方向为竖屏) -> 应用切换至前台(**应用方向为横屏**)
343
344| 名称                               | 值  | 可旋转方向           | 是否跟随传感器自动旋转 | 是否受旋转开关控制 |
345|----------------------------------|----|-----------------|-------------|-----------|
346| AUTO_ROTATION_RESTRICTED         | 8  | 横屏、竖屏、反向竖屏、反向横屏 | 是           | 是         |
347| AUTO_ROTATION_PORTRAIT_RESTRICTED         | 9  | 竖屏、反向竖屏 | 是           | 是         |
348| AUTO_ROTATION_LANDSCAPE_RESTRICTED         | 10 | 横屏、反向横屏 | 是           | 是         |
349| AUTO_ROTATION_UNSPECIFIED         | 12  | 受系统判定 | 是           | 是         |
350| USER_ROTATION_PORTRAIT           | 13 | 受系统判定           | 是           | 是         |
351| USER_ROTATION_LANDSCAPE          | 14 | 受系统判定           | 是           | 是         |
352| USER_ROTATION_PORTRAIT_INVERTED  | 15 | 受系统判定           | 是           | 是         |
353| USER_ROTATION_LANDSCAPE_INVERTED | 16 | 受系统判定           | 是           | 是         |
354
355<!--no_check-->