目录

Immersive Window

Overview

The immersive mode is a design mode that reduces interference from irrelevant elements to make the app UI more focused on content display, thereby improving user experience. A full-screen app window typically consists of the following UI elements: status bar, app UI, and bottom navigation bar. The status bar and navigation bar are called avoid areas in immersive mode, and the areas outside the avoid areas are called safe areas (as shown in the following figure). To develop an immersive page, you can extend the app page to the status bar and navigation bar to achieve the following purposes:

This topic describes the immersive development principles and implementation schemes, and provides solutions to adaptation problems in common immersive page development scenarios.

How to Implement

The implementation of the immersive window is based on the following factors:

  1. Immersive effect: Use specific methods, attributes, or APIs to extend pages beyond the safe area or title bar to the target area.

    The immersive effect of a page can be implemented at the window and component levels.

    • Window level: App-level global immersion, which takes effect on all pages.
    • Component level: The immersive effect takes effect on the current component. You can configure the immersive effect for multiple components on a single page.
  2. Avoidance: Prevent page content from being blocked or conflicting with the system information (such as battery level and time), interaction features (such as navigation bar gestures), or window control keys (such as close and minimize) in the avoid areas.

[h2]Implementing the Immersive Effect

The following table compares the solutions.

Item

Immersive Component Background

Immersive Component Page

Safe Area Extension

Immersive Window Display

Level

Component

Component

Component

Window

Description

Only the background extends to the avoid area. The content is in the safe area by default.

Both the background and content extend to the avoid area.

Only the background extends to the avoid area. The content is in the safe area by default.

The system safe area type and extension direction can be specified.

The layouts of all pages extend to the full screen, and automatic avoidance is not performed.

Usage scenario

Only the page background should be immersive.

The component content needs to completely cover the screen.

The extension area type needs to be specified for partial extension.

All pages of the app need to be immersive.

Advantage

Easy to use and understand.

One-time configuration can adapt to different window modes and directions.

Extension of multiple components with different backgrounds is supported.

Easy to use and understand.

One-time configuration can adapt to different window modes and directions.

Different safe areas can be extended.

Child components are still deployed in the safe area, and no additional avoidance processing is required.

Globally effective, with centralized adaptation logic.

Disadvantage

The scrolling content cannot extend to the avoid area.

Separate configuration is required for each page.

The content is prone to conflict with the elements in the avoid area, and manual processing is required.

Separate configuration is required for each page.

The scrolling content cannot extend to the avoid area.

The parameters are complex and hard to understand.

You need to manually calculate the height of the avoid area and process all content avoidance.

The immersive effect of a window is implemented by different pages, and the immersive effect of a page is implemented by the combination of immersive policies of different components. To implement the immersive effect of an app, you are advised to configure different immersive policies for each page through the component-level solution.

[h2]Avoidance Processing

The avoid area may contain content (such as the battery level and time in the status bar) or gesture interaction (such as tapping or swiping up on the navigation bar). After the immersive effect of the app page is implemented, UI elements in the avoid area may be blocked, or visual or interaction conflicts may occur. In this case, you can select a proper method to adapt to different scenarios.

[h2]Immersive Title Bar in the Freeform Window

In freeform window on PCs, tablets, and Mate XTs devices, you can set the title bar of an app window to be invisible to extend the app page to the title bar, implementing immersive display of the window. The component-level solution does not apply to the title bar of the freeform window. You need to customize the solution.

The title bar of a freeform window contains the app icon, app name, and three buttons (full screen/restore, minimize, and close). You can set the title bar to invisible to hide the app icon and app name, and retain the three buttons to implement the immersive window effect.

Extension of the Top or Bottom Background

[h2]When to Use

The page background needs to be extended to the status bar and navigation bar, and the page content is displayed in the safe area.

Full Screen

Split Screen

Floating Window

[h2]How to Develop

  1. Solution 1: Setting an immersive background for the component

    Set background() for the component to extend the background. The content is automatically retained in the safe area and adapts to the avoid area changes in different window modes and directions.

    Column() {
      // ...
    }
    // Add a background for the component to achieve immersive background effect
    .background('#F1F3F5')
  2. Solution 2: Setting an immersive page and avoid area for the component
    • Call ignoreLayoutSafeArea() and set the height to LayoutPolicy.matchParent to adapt to the parent component, and extend the page to the avoid area.
      Column() {
        // ...
      }
      // Expands the layout safe area of a component.
      .ignoreLayoutSafeArea()
      .height(LayoutPolicy.matchParent)
    • Call Window.getWindowAvoidArea() to obtain the heights of the status bar and navigation bar and record the heights using the status variable avoidSystem.
      // Get the avoid area.
      this.mainWindowInfo.avoidSystem = this.mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
    • Use the on('avoidAreaChange') event to listen for the avoid area changes and update the status variable avoidSystem in the listener callback.
      public onAvoidAreaChange: (avoidOptions: window.AvoidAreaOptions) => void =
        (avoidOptions: window.AvoidAreaOptions) => {
          if (avoidOptions.type === window.AvoidAreaType.TYPE_SYSTEM) {
            // Default area of the system.
            this.mainWindowInfo.avoidSystem = avoidOptions.area;
          } else if (avoidOptions.type === window.AvoidAreaType.TYPE_CUTOUT) {
            // Cutout area.
            this.mainWindowInfo.avoidCutout = avoidOptions.area;
            this.updateAvoidPadding(avoidOptions.area);
          } else if (avoidOptions.type === window.AvoidAreaType.TYPE_SYSTEM_GESTURE) {
            // Side return gesture area.
            this.mainWindowInfo.avoidSystemGesture = avoidOptions.area;
          } else if (avoidOptions.type === window.AvoidAreaType.TYPE_KEYBOARD) {
            // Fixed soft keyboard area.
            this.mainWindowInfo.avoidKeyboard = avoidOptions.area;
          } else if (avoidOptions.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {
            // Bottom navigation bar.
            this.mainWindowInfo.avoidNavigationIndicator = avoidOptions.area;
          }
        };
    • Set the top and bottom padding of the component to the heights of the status bar and navigation bar respectively so that the content is displayed only in the safe area.
      Column() {
        // ...
      }
      // ...
      // Set the top and bottom padding to avoid status bar and navigation bar.
      .padding({
        top: this.windowUtil?.mainWindowInfo.avoidSystem?.topRect.height + 'px',
        bottom: this.windowUtil?.mainWindowInfo.avoidNavigationIndicator?.bottomRect.height + 'px'
      })

    You are advised to use the preceding two solutions, which are easier to understand and implement than the immersive window display and safe area extension solutions. In addition, the two solutions automatically adapt to different window modes and directions.

Notch Avoidance

[h2]When to Use

In scenarios where the visible area of the screen needs to be fully utilized, to display important information or operation buttons on the status bar, you need to not only hide the original status bar and navigation bar, but also avoid the cutout area. In this case, you can make the background fully immersive and avoid the cutout area in the content area.

In the following scenarios, the cutout area size may change. Therefore, you need to listen for the avoid area height and other changes to ensure that the UI layout is adjusted timely.

The following figures show the device rotation effect.

Portrait with Top Notch

Landscape with Left Notch

Portrait with Bottom Notch

Inverted Landscape with Right Notch

[h2]How to Develop

  1. Use ignoreLayoutSafeArea() and height(LayoutPolicy.matchParent) to implement an immersive page.
    Column() {
      // ...
    }
    // Expands the layout safe area of a component.
    .ignoreLayoutSafeArea()
    .height(LayoutPolicy.matchParent)
  2. Use setWindowSystemBarEnable() to hide the status bar and navigation bar.
    // Hide the status bar and navigation bar.
    this.mainWindow.setWindowSystemBarEnable([]).catch((error: BusinessError) => {
      let err = error as BusinessError;
      hilog.error(0x0000, 'testLog', `setWindowSystemBarEnable failed. Code:${err.code}, message:${err.message}`);
    });
  3. Use on('avoidAreaChange') to dynamically listen for the avoid area change, and obtain the cutout area information using AvoidAreaType.TYPE_CUTOUT.
    public onAvoidAreaChange: (avoidOptions: window.AvoidAreaOptions) => void =
      (avoidOptions: window.AvoidAreaOptions) => {
        if (avoidOptions.type === window.AvoidAreaType.TYPE_SYSTEM) {
          // Default area of the system.
          this.mainWindowInfo.avoidSystem = avoidOptions.area;
        } else if (avoidOptions.type === window.AvoidAreaType.TYPE_CUTOUT) {
          // Cutout area.
          this.mainWindowInfo.avoidCutout = avoidOptions.area;
          this.updateAvoidPadding(avoidOptions.area);
        } else if (avoidOptions.type === window.AvoidAreaType.TYPE_SYSTEM_GESTURE) {
          // Side return gesture area.
          this.mainWindowInfo.avoidSystemGesture = avoidOptions.area;
        } else if (avoidOptions.type === window.AvoidAreaType.TYPE_KEYBOARD) {
          // Fixed soft keyboard area.
          this.mainWindowInfo.avoidKeyboard = avoidOptions.area;
        } else if (avoidOptions.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {
          // Bottom navigation bar.
          this.mainWindowInfo.avoidNavigationIndicator = avoidOptions.area;
        }
      };
  4. Determine the avoidance direction based on the position of the cutout area and record the direction in the status variable avoidAreaPadding.
    • If the cutout area is at the top, the top avoid distance is calculated as follows: Distance between the cutout area and the top edge of the screen + Height of the cutout area.
    • If the cutout area is on the left, the left avoid distance is calculated as follows: Distance between the cutout area and the left edge of the screen + Width of the cutout area.
    • If the cutout area is on the right, the right avoid distance is calculated as follows: Screen width – Distance between the cutout area and the left edge of the screen.
    • If the cutout area is at the bottom, the bottom avoid distance is calculated as follows: Screen height – Distance between the cutout area and the top edge of the screen.
    updateAvoidPadding(area: window.AvoidArea) {
      const avoidAreaPadding: Padding = {};
      try {
        // Top cutout area: set top padding.
        if (area.topRect.height > 0) {
          avoidAreaPadding.top = this.uiContext?.px2vp(area.topRect.height + area.topRect.top);
        }
        // Left cutout area: set left padding.
        if (area.leftRect.width > 0) {
          avoidAreaPadding.left = this.uiContext?.px2vp(area.leftRect.left + area.leftRect.width);
        }
        // Right cutout area: set right padding.
        if (area.rightRect.width > 0) {
          avoidAreaPadding.right = this.uiContext?.px2vp(display.getDefaultDisplaySync().width - area.rightRect.left);
        }
        // Bottom cutout area: set bottom padding.
        if (area.bottomRect.height > 0) {
          avoidAreaPadding.bottom = this.uiContext?.px2vp(display.getDefaultDisplaySync().height - area.bottomRect.top);
        }
      } catch (error) {
        let err = error as BusinessError;
        hilog.error(0x0000, 'TestLog', `Failed to set avoid padding. Code: ${err.code}, message: ${err.message}`);
      }
      this.mainWindowInfo.avoidAreaPadding = avoidAreaPadding;
    }
  5. Set the padding of the component for avoidance.
    Column() {
      // ...
    }
    // ...
    // Set paddings to avoid notch.
    .padding(this.mainWindowInfo?.avoidAreaPadding)

Immersive Title Bar in the Freeform Window

[h2]When to Use

In a freeform window, you need to hide the default title bar and reserve the close, minimize, and maximize buttons so that the page can extend to the original title bar.

[h2]How to Develop

  1. Call setWindowDecorVisible(false) to hide the title bar and reserve the three buttons in the upper right corner.
    this.mainWindow.setWindowDecorVisible(false);
  2. Call setWindowDecorHeight() to set the height of the title bar and control the display of the three buttons in the upper-right corner.
    this.mainWindow.setWindowDecorHeight(56);
  3. Call setDecorButtonStyle() to set the size of the buttons in the upper right corner to be the same as that of the icon on the top of the page.
    this.mainWindow.setDecorButtonStyle({ buttonIconSize: 24 });
  4. Call on('windowTitleButtonRectChange') to register a listener for the size change of the three buttons in the upper right corner for page layout avoidance.
    public onWindowButtonRectChange: (titleButtonRect: window.TitleButtonRect) => void =
      (titleButtonRect: window.TitleButtonRect) => {
        // Update the rectangle information of the title bar button.
        this.mainWindowInfo.titleButtonRect = titleButtonRect;
      }
  5. Use the padding for layout avoidance.
    Column() {
      // ...
    }
    .padding({
      right: this.mainWindowInfo.isImmersive === ImmersiveType.IMMERSIVE ? this.mainWindowInfo.titleButtonRect?.width :
        0
    })

Sample Code

Immersive Effect