DEV Community

xhunmon
xhunmon

Posted on

Part 5: Implementing Immersive Effects in HarmonyOS

In HarmonyOS app development, immersive experience is an important way to enhance UI aesthetics and user interaction. Immersive effects usually mean that page content can extend into the system status bar and navigation bar areas, creating a borderless visual experience. This article details how to implement immersive effects in HarmonyOS ArkTS projects, including full-screen settings, status/navigation bar adaptation, and reusable gradient header components.

1. Key Steps to Achieve Immersive Effects

1. Set Full-Screen Window and System Bar Properties

HarmonyOS provides various window management APIs. For immersive effects, it is recommended to use a "full-screen layout + transparent/custom system bar" approach:

let isLayoutFullScreen = true;
windowClass.setWindowLayoutFullScreen(isLayoutFullScreen, (err: BusinessError) => {
  if (err.code) {
    console.error('Failed to set the window layout to full-screen mode. Cause:' + JSON.stringify(err));
    return;
  }
  console.info('Succeeded in setting the window layout to full-screen mode.');
});
let sysBarProps: window.SystemBarProperties = {
  statusBarColor: '#ff00ff',
  navigationBarColor: '#00ff00',
  statusBarContentColor: '#ffffff',
  navigationBarContentColor: '#ffffff'
};
windowClass.setWindowSystemBarProperties(sysBarProps, (err: BusinessError) => {
  if (err.code) {
    console.error('Failed to set the system bar properties. Cause: ' + JSON.stringify(err));
    return;
  }
  console.info('Succeeded in setting the system bar properties.');
});
Enter fullscreen mode Exit fullscreen mode

2. Obtain Status Bar and Navigation Bar Heights

In the aboutToAppear lifecycle of the EntryView page, use window.getLastWindow(getContext()) to get the window object, then use getWindowAvoidArea to get the heights of the status bar and navigation bar, and store them in global variables:

aboutToAppear(): void {
  window.getLastWindow(getContext()).then((lastWindow) => {
    let areas = lastWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);
    const statusHeight = px2vp(areas.topRect.height);
    areas = lastWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
    const navHeight = px2vp(areas.bottomRect.height);
    AppStorage.setOrCreate('statusHeight', statusHeight);
    AppStorage.setOrCreate('navHeight', navHeight);
  });
}
Enter fullscreen mode Exit fullscreen mode

3. Page Adaptation and Placeholder Handling

In pages that need adaptation (such as MainPage, HomePage), use the @StorageProp decorator to get the global height variables, and reserve space for the status bar and navigation bar in the layout:

@StorageProp('statusHeight') statusHeight: number = 0;
@StorageProp('navHeight') navHeight: number = 0;
...
Line().height(this.navHeight).visibility(Visibility.Hidden)
Enter fullscreen mode Exit fullscreen mode

4. Gradient Immersive Header Component

By customizing a Header component with linear gradient, status bar height placeholder, back button, and right-side custom layout, you can achieve a highly reusable immersive header:

@Component
export struct Header {
  @Require @Prop title: string | Resource;
  onKeyBack?: () => void;
  @BuilderParam rightLayout?: () => void;
  titleBarHeight: Length = 45;
  titleSize: number | string | Resource = '18fp';
  titleAttrModifier: AttributeModifier<TextAttribute> = {};
  bgTopColor: ResourceColor = '#74C678';
  bgBottomColor: ResourceColor = '#266B29';
  titleColor: ResourceColor = Color.White;
  @StorageProp('statusHeight') statusHeight: number = 0;
  build() {
    Stack() {
      RelativeContainer() {
        Text(this.title)
          .fontSize(this.titleSize)
          .width('50%')
          .height('100%')
          .fontColor(this.titleColor)
          .fontWeight(FontWeight.Medium)
          .ellipsisMode(EllipsisMode.END)
          .textOverflow({ overflow: TextOverflow.Ellipsis })
          .maxLines(1)
          .textAlign(TextAlign.Center)
          .alignRules({ middle: { anchor: "__container__", align: HorizontalAlign.Center } })
          .id("i1")
          .attributeModifier(this.titleAttrModifier)
        if (this.onKeyBack) {
          Image($r('app.media.ic_back'))
            .height('100%')
            .padding({ left: 16, top: 11, bottom: 11, right: 11 })
            .fillColor(this.titleColor)
            .objectFit(ImageFit.Contain)
            .alignRules({ left: { anchor: "__container__", align: HorizontalAlign.Start } })
            .id("i2")
            .onClick(() => { this.onKeyBack?.() })
        }
        if (this.rightLayout) {
          Row() { this.rightLayout?.() }
            .height('100%')
            .justifyContent(FlexAlign.End)
            .alignRules({ right: { anchor: "__container__", align: HorizontalAlign.End } })
            .id("i3")
        }
      }
      .width('100%')
      .height(this.titleBarHeight)
    }
    .width('100%')
    .padding({ top: this.statusHeight })
    .backgroundColor(this.bgTopColor)
    .linearGradient({
      angle: 0,
      colors: [ [this.bgTopColor, 0.0], [this.bgBottomColor, 1.0] ]
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Best Practices and Official Documentation

  • Recommended reading: Window Management and Immersive Effects Official Guide
  • ArkTS Coding Style Guide
  • It is recommended to encapsulate the immersive header as a common component for reuse across multiple pages.
  • Store status bar and navigation bar heights globally to avoid redundant calculations.
  • Visual details such as gradients, rounded corners, and transparency can be flexibly adjusted according to product style.

Note: The state management in this article uses V1. The open-source project has been upgraded to V2. Please upgrade accordingly.

All content for this chapter is complete! The full source code has been uploaded to Gitee: HarmonyOS App 0-1 Development.

Top comments (0)