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