• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Application Window Development (Stage Model)
2
3
4## Basic Concepts
5
6- Immersive window: a window display mode where the system windows (generally the status bar and navigation bar) are hidden to allow users to fully engage with the content.
7
8  The immersive window feature is applicable only to the main window of an application in full-screen mode. It does not apply to a main window in freeform window mode or a subwindow (for example, a dialog box or a floating window).
9
10- Floating window: a special application window that can still be displayed in the foreground when the main window and corresponding ability are running in the background.
11
12  The floating window can be used to continue playing a video after the application is switched to the background, or offer a quick entry (for example, bubbles) to the application. Before creating a floating window, an application must apply for the required permission.
13
14
15## When to Use
16
17In the stage model, you can perform the following operations during application window development:
18
19- Setting the properties and content of the main window of an application
20
21- Setting the properties and content of the subwindow of an application
22
23- Experiencing the immersive window feature
24
25- Setting a floating window
26
27- Listening for interactive and non-interactive window events
28
29## Available APIs
30
31The table below lists the common APIs used for application window development. For details about more APIs, see [Window](../reference/apis-arkui/js-apis-window.md).
32
33| Instance        | API                                                      | Description                                                        |
34| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
35| WindowStage    | getMainWindow(callback: AsyncCallback&lt;Window&gt;): void   | Obtains the main window of this window stage.<br>This API can be used only in the stage model.|
36| WindowStage    | loadContent(path: string, callback: AsyncCallback&lt;void&gt;): void | Loads content to the main window in this window stage.<br>**path**: path of the page from which the content will be loaded. The path is configured in the **main_pages.json** file of the project.<br>This API can be used only in the stage model.|
37| WindowStage    | createSubWindow(name: string, callback: AsyncCallback&lt;Window&gt;): void | Creates a subwindow.<br>This API can be used only in the stage model.            |
38| WindowStage    | on(type: 'windowStageEvent', callback: Callback&lt;WindowStageEventType&gt;): void | Subscribes to window stage lifecycle change events.<br>This API can be used only in the stage model.|
39| Window static method| createWindow(config: Configuration, callback: AsyncCallback\<Window>): void | Creates a subwindow or system window.<br>**config**: parameters used for creating the window.            |
40| Window         | setUIContent(path: string, callback: AsyncCallback&lt;void&gt;): void | Loads the content of a page, with its path in the current project specified, to this window.<br>**path**: path of the page from which the content will be loaded. The path is configured in the **main_pages.json** file of the project in the stage model.                                    |
41| Window         | setWindowBrightness(brightness: number, callback: AsyncCallback&lt;void&gt;): void | Sets the brightness for this window.                                            |
42| Window         | setWindowTouchable(isTouchable: boolean, callback: AsyncCallback&lt;void&gt;): void | Sets whether this window is touchable.                                    |
43| Window         | moveWindowTo(x: number, y: number, callback: AsyncCallback&lt;void&gt;): void | Moves this window.                                          |
44| Window         | resize(width: number, height: number, callback: AsyncCallback&lt;void&gt;): void | Changes the window size.                                          |
45| Window         | setWindowLayoutFullScreen(isLayoutFullScreen: boolean): Promise&lt;void&gt; | Sets whether to enable the full-screen mode for the window layout.                                 |
46| Window         | setWindowSystemBarEnable(names: Array&lt;'status'\|'navigation'&gt;): Promise&lt;void&gt; | Sets whether to display the status bar and navigation bar in this window.                                |
47| Window         | setWindowSystemBarProperties(systemBarProperties: SystemBarProperties): Promise&lt;void&gt; | Sets the properties of the status bar and navigation bar in this window.<br>**systemBarProperties**: properties of the status bar and navigation bar.|
48| Window         | showWindow(callback: AsyncCallback\<void>): void             | Shows this window.                                              |
49| Window         | on(type: 'touchOutside', callback: Callback&lt;void&gt;): void | Subscribes to touch events outside this window.                          |
50| Window         | destroyWindow(callback: AsyncCallback&lt;void&gt;): void     | Destroys this window.                                              |
51
52
53## Setting the Main Window of an Application
54
55In the stage model, the main window of an application is created and maintained by a **UIAbility** instance. In the **onWindowStageCreate** callback of the **UIAbility** instance, use **WindowStage** to obtain the main window of the application and set its properties. You can also set the properties (for example, **maxWindowWidth**) in the [module.json5 file](../quick-start/module-configuration-file.md#abilities).
56
57### How to Develop
58
591. Obtain the main window.
60
61   Call **getMainWindow** to obtain the main window of the application.
62
632. Set the properties of the main window.
64
65   You can set multiple properties of the main window, such as the background color, brightness, and whether the main window is touchable. The code snippet below uses the **touchable** property as an example.
66
673. Load content to the main window.
68
69   Call **loadContent** to load content to the main window.
70
71```ts
72import { UIAbility } from '@kit.AbilityKit';
73import { window } from '@kit.ArkUI';
74import { BusinessError } from '@kit.BasicServicesKit';
75
76export default class EntryAbility extends UIAbility {
77  onWindowStageCreate(windowStage: window.WindowStage) {
78    // 1. Obtain the main window of the application.
79    let windowClass: window.Window | null = null;
80    windowStage.getMainWindow((err: BusinessError, data) => {
81      let errCode: number = err.code;
82      if (errCode) {
83        console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
84        return;
85      }
86      windowClass = data;
87      console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data));
88      // 2. Set the touchable property of the main window.
89      let isTouchable: boolean = true;
90      windowClass.setWindowTouchable(isTouchable, (err: BusinessError) => {
91        let errCode: number = err.code;
92        if (errCode) {
93          console.error('Failed to set the window to be touchable. Cause:' + JSON.stringify(err));
94          return;
95        }
96        console.info('Succeeded in setting the window to be touchable.');
97      })
98    })
99    // 3. Load content to the main window.
100    windowStage.loadContent("pages/page2", (err: BusinessError) => {
101      let errCode: number = err.code;
102      if (errCode) {
103        console.error('Failed to load the content. Cause:' + JSON.stringify(err));
104        return;
105      }
106      console.info('Succeeded in loading the content.');
107    });
108  }
109};
110```
111
112## Setting a Subwindow of an Application
113
114You can create an application subwindow, such as a dialog box, and set its properties.
115
116### How to Develop
117
1181. Create a subwindow.
119
120   Call **createSubWindow** to create a subwindow.
121
1222. Set the properties of the subwindow.
123
124   After the subwindow is created, you can set its properties, such as the size, position, background color, and brightness.
125
1263. Load content to and show the subwindow.
127
128   Call **setUIContent** to load content to the subwindow and **showWindow** to show the subwindow.
129
1304. Destroy the subwindow.
131
132   When the subwindow is no longer needed, you can call **destroyWindow** to destroy it.
133
134The code snippet for creating a subwindow in **onWindowStageCreate** is as follows:
135
136```ts
137import { UIAbility } from '@kit.AbilityKit';
138import { window } from '@kit.ArkUI';
139import { BusinessError } from '@kit.BasicServicesKit';
140
141let windowStage_: window.WindowStage | null = null;
142let sub_windowClass: window.Window | null = null;
143
144export default class EntryAbility extends UIAbility {
145  showSubWindow() {
146    // 1. Create a subwindow.
147    if (windowStage_ == null) {
148      console.error('Failed to create the subwindow. Cause: windowStage_ is null');
149    }
150    else {
151      windowStage_.createSubWindow("mySubWindow", (err: BusinessError, data) => {
152        let errCode: number = err.code;
153        if (errCode) {
154          console.error('Failed to create the subwindow. Cause: ' + JSON.stringify(err));
155          return;
156        }
157        sub_windowClass = data;
158        console.info('Succeeded in creating the subwindow. Data: ' + JSON.stringify(data));
159        // 2. Set the position, size, and other properties of the subwindow.
160        sub_windowClass.moveWindowTo(300, 300, (err: BusinessError) => {
161          let errCode: number = err.code;
162          if (errCode) {
163            console.error('Failed to move the window. Cause:' + JSON.stringify(err));
164            return;
165          }
166          console.info('Succeeded in moving the window.');
167        });
168        sub_windowClass.resize(500, 500, (err: BusinessError) => {
169          let errCode: number = err.code;
170          if (errCode) {
171            console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
172            return;
173          }
174          console.info('Succeeded in changing the window size.');
175        });
176        // 3.1 Load content to the subwindow.
177        sub_windowClass.setUIContent("pages/page3", (err: BusinessError) => {
178          let errCode: number = err.code;
179          if (errCode) {
180            console.error('Failed to load the content. Cause:' + JSON.stringify(err));
181            return;
182          }
183          console.info('Succeeded in loading the content.');
184          // 3.2 Show the subwindow.
185          (sub_windowClass as window.Window).showWindow((err: BusinessError) => {
186            let errCode: number = err.code;
187            if (errCode) {
188              console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
189              return;
190            }
191            console.info('Succeeded in showing the window.');
192          });
193        });
194      })
195    }
196  }
197
198  destroySubWindow() {
199    // 4. Destroy the subwindow when it is no longer needed (depending on the service logic).
200    (sub_windowClass as window.Window).destroyWindow((err: BusinessError) => {
201      let errCode: number = err.code;
202      if (errCode) {
203        console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
204        return;
205      }
206      console.info('Succeeded in destroying the window.');
207    });
208  }
209
210  onWindowStageCreate(windowStage: window.WindowStage) {
211    windowStage_ = windowStage;
212    // Create a subwindow when it is needed, for example, when a touch event occurs in the main window. Calling onWindowStageCreate is not always necessary. The code here is for reference only.
213    this.showSubWindow();
214  }
215
216  onWindowStageDestroy() {
217    // Destroy the subwindow when it is no longer needed, for example, when the Close button in the subwindow is touched. Calling onWindowStageDestroy is not always necessary. The code here is for reference only.
218    this.destroySubWindow();
219  }
220};
221```
222
223You can also click a button on a page to create a subwindow. The code snippet is as follows:
224
225```ts
226// EntryAbility.ets
227onWindowStageCreate(windowStage: window.WindowStage) {
228  windowStage.loadContent('pages/Index', (err) => {
229    if (err.code) {
230      console.error('Failed to load the content. Cause:' + JSON.stringify(err));
231      return;
232    }
233    console.info('Succeeded in loading the content.');
234  })
235
236  // Transfer the window stage to the Index page.
237  AppStorage.setOrCreate('windowStage', windowStage);
238}
239```
240
241```ts
242// Index.ets
243import { window } from '@kit.ArkUI';
244import { BusinessError } from '@kit.BasicServicesKit';
245
246let windowStage_: window.WindowStage | undefined = undefined;
247let sub_windowClass: window.Window | undefined = undefined;
248@Entry
249@Component
250struct Index {
251  @State message: string = 'Hello World';
252  private CreateSubWindow(){
253    // Obtain the window stage.
254    windowStage_ = AppStorage.get('windowStage');
255    // 1. Create a subwindow.
256    if (windowStage_ == null) {
257      console.error('Failed to create the subwindow. Cause: windowStage_ is null');
258    }
259    else {
260      windowStage_.createSubWindow("mySubWindow", (err: BusinessError, data) => {
261        let errCode: number = err.code;
262        if (errCode) {
263          console.error('Failed to create the subwindow. Cause: ' + JSON.stringify(err));
264          return;
265        }
266        sub_windowClass = data;
267        console.info('Succeeded in creating the subwindow. Data: ' + JSON.stringify(data));
268        // 2. Set the position, size, and other properties of the subwindow.
269        sub_windowClass.moveWindowTo(300, 300, (err: BusinessError) => {
270          let errCode: number = err.code;
271          if (errCode) {
272            console.error('Failed to move the window. Cause:' + JSON.stringify(err));
273            return;
274          }
275          console.info('Succeeded in moving the window.');
276        });
277        sub_windowClass.resize(500, 500, (err: BusinessError) => {
278          let errCode: number = err.code;
279          if (errCode) {
280            console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
281            return;
282          }
283          console.info('Succeeded in changing the window size.');
284        });
285        // 3. Load content to the subwindow.
286        sub_windowClass.setUIContent("pages/subWindow", (err: BusinessError) => {
287          let errCode: number = err.code;
288          if (errCode) {
289            console.error('Failed to load the content. Cause:' + JSON.stringify(err));
290            return;
291          }
292          console.info('Succeeded in loading the content.');
293          // 3. Show the subwindow.
294          (sub_windowClass as window.Window).showWindow((err: BusinessError) => {
295            let errCode: number = err.code;
296            if (errCode) {
297              console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
298              return;
299            }
300            console.info('Succeeded in showing the window.');
301          });
302        });
303      })
304    }
305  }
306  private destroySubWindow(){
307    // 4. Destroy the subwindow when it is no longer needed (depending on the service logic).
308    (sub_windowClass as window.Window).destroyWindow((err: BusinessError) => {
309      let errCode: number = err.code;
310      if (errCode) {
311        console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
312        return;
313      }
314      console.info('Succeeded in destroying the window.');
315    });
316  }
317  build() {
318    Row() {
319      Column() {
320        Text(this.message)
321          .fontSize(50)
322          .fontWeight(FontWeight.Bold)
323        Button(){
324          Text('CreateSubWindow')
325          .fontSize(24)
326          .fontWeight(FontWeight.Normal)
327        }.width(220).height(68)
328        .margin({left:10, top:60})
329        .onClick(() => {
330          this.CreateSubWindow()
331        })
332        Button(){
333          Text('destroySubWindow')
334          .fontSize(24)
335          .fontWeight(FontWeight.Normal)
336        }.width(220).height(68)
337        .margin({left:10, top:60})
338        .onClick(() => {
339          this.destroySubWindow()
340        })
341      }
342      .width('100%')
343    }
344    .height('100%')
345  }
346}
347```
348
349```ts
350// subWindow.ets
351@Entry
352@Component
353struct SubWindow {
354  @State message: string = 'Hello subWindow';
355  build() {
356    Row() {
357      Column() {
358        Text(this.message)
359          .fontSize(50)
360          .fontWeight(FontWeight.Bold)
361      }
362      .width('100%')
363    }
364    .height('100%')
365  }
366}
367```
368
369## Experiencing the Immersive Window Feature
370
371To create a better video watching and gaming experience, you can use the immersive window feature to hide the status bar and navigation bar. This feature is available only for the main window of an application. Since API version 10, the immersive window has the same size as the full screen by default; its layout is controlled by the component module; the background color of its status bar and navigation bar is transparent, and the text color is black. When an application window calls **setWindowLayoutFullScreen**, with **true** passed in, an immersive window layout is used. If **false** is passed in, a non-immersive window layout is used.
372
373> **NOTE**
374>
375> Currently, immersive UI development supports window-level configuration, but not page-level configuration. If page redirection is required, you can set the immersive mode at the beginning of the page lifecycle, for example, in the **onPageShow** callback, and then restore the default settings when the page exits, for example, in the **onPageHide** callback.
376
377### How to Develop
378
3791. Obtain the main window.
380
381   Call **getMainWindow** to obtain the main window of the application.
382
3832. Implement the immersive effect. You can use either of the following methods:
384
385   - Method 1: When the main window of the application is a full-screen window, call **setWindowSystemBarEnable** to hide the status bar and navigation bar.
386
387   - Method 2: Call **setWindowLayoutFullScreen** to enable the full-screen mode for the main window layout. Call **setWindowSystemBarProperties** to set the opacity, background color, text color, and highlighted icon of the status bar and navigation bar to create a display effect consistent with that of the main window.
388
3893. Load content to the immersive window.
390
391   Call **loadContent** to load content to the immersive window.
392
393```ts
394import { UIAbility } from '@kit.AbilityKit';
395import { window } from '@kit.ArkUI';
396import { BusinessError } from '@kit.BasicServicesKit';
397
398export default class EntryAbility extends UIAbility {
399  onWindowStageCreate(windowStage: window.WindowStage) {
400    // 1. Obtain the main window of the application.
401    let windowClass: window.Window | null = null;
402    windowStage.getMainWindow((err: BusinessError, data) => {
403      let errCode: number = err.code;
404      if (errCode) {
405        console.error('Failed to obtain the main window. Cause: ' + JSON.stringify(err));
406        return;
407      }
408      windowClass = data;
409      console.info('Succeeded in obtaining the main window. Data: ' + JSON.stringify(data));
410
411      // 2. Implement the immersive effect by hiding the status bar and navigation bar.
412      let names: Array<'status' | 'navigation'> = [];
413      windowClass.setWindowSystemBarEnable(names)
414        .then(() => {
415          console.info('Succeeded in setting the system bar to be visible.');
416        })
417        .catch((err: BusinessError) => {
418          console.error('Failed to set the system bar to be visible. Cause:' + JSON.stringify(err));
419        });
420      // 2. Alternatively, implement the immersive effect by setting the properties of the status bar and navigation bar.
421      let isLayoutFullScreen = true;
422      windowClass.setWindowLayoutFullScreen(isLayoutFullScreen)
423        .then(() => {
424          console.info('Succeeded in setting the window layout to full-screen mode.');
425        })
426        .catch((err: BusinessError) => {
427          console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
428        });
429      let sysBarProps: window.SystemBarProperties = {
430        statusBarColor: '#ff00ff',
431        navigationBarColor: '#00ff00',
432        // The following properties are supported since API version 8.
433        statusBarContentColor: '#ffffff',
434        navigationBarContentColor: '#ffffff'
435      };
436      windowClass.setWindowSystemBarProperties(sysBarProps)
437        .then(() => {
438          console.info('Succeeded in setting the system bar properties.');
439        })
440        .catch((err: BusinessError) => {
441          console.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err));
442        });
443    })
444    // 3. Load content to the immersive window.
445    windowStage.loadContent("pages/page2", (err: BusinessError) => {
446      let errCode: number = err.code;
447      if (errCode) {
448        console.error('Failed to load the content. Cause:' + JSON.stringify(err));
449        return;
450      }
451      console.info('Succeeded in loading the content.');
452    });
453  }
454};
455```
456
457<!--RP2-->
458## Setting a Floating Window<!--RP2End-->
459
460A floating window is created based on an existing task. It is always displayed in the foreground, even if the task used for creating the floating window is switched to the background. Generally, the floating window is above all application windows. You can create a floating window and set its properties.
461
462
463### How to Develop
464
465<!--RP1-->
466**Prerequisites**: To create a floating window (a window of the type **WindowType.TYPE_FLOAT**), you must request the **ohos.permission.SYSTEM_FLOAT_WINDOW** permission. For details, see [Requesting Permissions for system_basic Applications](../security/AccessToken/determine-application-mode.md#requesting-permissions-for-system_basic-applications).
467<!--RP1End-->
468
4691. Create a floating window.
470
471   Call **window.createWindow** to create a floating window.
472
4732. Set properties of the floating window.
474
475   After the floating window is created, you can set its properties, such as the size, position, background color, and brightness.
476
4773. Load content to and show the floating window.
478
479   Call **setUIContent** to load content to the floating window and **showWindow** to show the window.
480
4814. Destroy the floating window.
482
483   When the floating window is no longer needed, you can call **destroyWindow** to destroy it.
484
485```ts
486import { UIAbility } from '@kit.AbilityKit';
487import { window } from '@kit.ArkUI';
488import { BusinessError } from '@kit.BasicServicesKit';
489
490export default class EntryAbility extends UIAbility {
491  onWindowStageCreate(windowStage: window.WindowStage) {
492    // 1. Create a floating window.
493    let windowClass: window.Window | null = null;
494    let config: window.Configuration = {
495      name: "floatWindow", windowType: window.WindowType.TYPE_FLOAT, ctx: this.context
496    };
497    window.createWindow(config, (err: BusinessError, data) => {
498      let errCode: number = err.code;
499      if (errCode) {
500        console.error('Failed to create the floatWindow. Cause: ' + JSON.stringify(err));
501        return;
502      }
503      console.info('Succeeded in creating the floatWindow. Data: ' + JSON.stringify(data));
504      windowClass = data;
505      // 2. Set the position, size, and other properties of the floating window.
506      windowClass.moveWindowTo(300, 300, (err: BusinessError) => {
507        let errCode: number = err.code;
508        if (errCode) {
509          console.error('Failed to move the window. Cause:' + JSON.stringify(err));
510          return;
511        }
512        console.info('Succeeded in moving the window.');
513      });
514      windowClass.resize(500, 500, (err: BusinessError) => {
515        let errCode: number = err.code;
516        if (errCode) {
517          console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
518          return;
519        }
520        console.info('Succeeded in changing the window size.');
521      });
522      // 3.1 Load content to the floating window.
523      windowClass.setUIContent("pages/page4", (err: BusinessError) => {
524        let errCode: number = err.code;
525        if (errCode) {
526          console.error('Failed to load the content. Cause:' + JSON.stringify(err));
527          return;
528        }
529        console.info('Succeeded in loading the content.');
530        // 3.2 Show the floating window.
531        (windowClass as window.Window).showWindow((err: BusinessError) => {
532          let errCode: number = err.code;
533          if (errCode) {
534            console.error('Failed to show the window. Cause: ' + JSON.stringify(err));
535            return;
536          }
537          console.info('Succeeded in showing the window.');
538        });
539      });
540      // 4. Destroy the floating window when it is no longer needed (depending on the service logic).
541      windowClass.destroyWindow((err: BusinessError) => {
542        let errCode: number = err.code;
543        if (errCode) {
544          console.error('Failed to destroy the window. Cause: ' + JSON.stringify(err));
545          return;
546        }
547        console.info('Succeeded in destroying the window.');
548      });
549    });
550  }
551};
552```
553
554## Listening for Interactive and Non-Interactive Window Events
555
556When running in the foreground, an application may switch between interactive and non-interactive states and process services depending on the state. For example, when the user opens the **Recents** screen, an application becomes non-interactive and pauses the service interaction with the user, such as video playback or camera preview; when the user switched back to the foreground, the application becomes interactive again, and the paused service needs to be resumed.
557
558### How to Develop
559
560After a **WindowStage** object is created, the application can listen for the **'windowStageEvent'** event to obtain window stage lifecycle changes, for example, whether the window stage is interactive or non-interactive in the foreground. The application can process services based on the reported event status.
561
562```ts
563import { UIAbility } from '@kit.AbilityKit';
564import { window } from '@kit.ArkUI';
565
566export default class EntryAbility extends UIAbility {
567  onWindowStageCreate(windowStage: window.WindowStage) {
568    try {
569      windowStage.on('windowStageEvent', (data) => {
570        console.info('Succeeded in enabling the listener for window stage event changes. Data: ' +
571          JSON.stringify(data));
572
573        // Process services based on the event status.
574        if (data == window.WindowStageEventType.SHOWN) {
575          console.info('current window stage event is SHOWN');
576          // The application enters the foreground and is interactive by default.
577          // ...
578        } else if (data == window.WindowStageEventType.HIDDEN) {
579          console.info('current window stage event is HIDDEN');
580          // The application enters the background and is non-interactive by default.
581          // ...
582        } else if (data == window.WindowStageEventType.PAUSED) {
583          console.info('current window stage event is PAUSED');
584          // The user opens the Recents screen when the application is running in the foreground, and the application becomes non-interactive.
585          // ...
586        } else if (data == window.WindowStageEventType.RESUMED) {
587          console.info('current window stage event is RESUMED');
588          // The user switches back from the Recents screen to the application, and the application becomes interactive.
589          // ...
590        }
591
592        // ...
593      });
594    } catch (exception) {
595      console.error('Failed to enable the listener for window stage event changes. Cause:' +
596        JSON.stringify(exception));
597    }
598  }
599}
600```
601