DEV Community

Cover image for Component Rotation, Notification Management Issues, Window Status Acquisition
kouwei qing
kouwei qing

Posted on

Component Rotation, Notification Management Issues, Window Status Acquisition

[Daily HarmonyOS Next Knowledge] Component Rotation, Notification Management Issues, Window Status Acquisition, Foreground/Background Switch Monitoring, Differences Between Conditional Judgment and Visibility Control

1. HarmonyOS component translation direction error after rotation?

After component rotation, the x and y axes of the component remain in their original directions.

import json from '@ohos.util.json'

@Entry
@Component
struct Index {
  @State imageWidth: number = 0
  @State imageHeight: number = 0
  @State offsetX: number = 0
  @State offsetY: number = 0
  @State positionX: number = 0
  @State positionY: number = 0
  @State angle: number = 0
  @State rotateValue: number = 0
  @State scaleValue: number = 1
  @State pinchValue: number = 1
  @State pinchX: number = 0
  @State pinchY: number = 0
  @State centerX: number = 0
  @State centerY: number = 0

  aboutToAppear(): void {

  }

  build() {
    Column() {
      Text('Title Bar')
        .width('100%')
        .height(50)
        .textAlign(TextAlign.Center)

      Column() {
        Image($r('app.media.img'))
          .width(200)
          .height(200)
          .scale({ x: this.scaleValue, y: this.scaleValue, z: 1 })
          .translate({ x: this.offsetX, y: this.offsetY, z: 0 })
          .rotate({
            angle: this.angle,
          })
          .gesture(GestureGroup(GestureMode.Parallel,
            PanGesture()
              .onActionUpdate((event: GestureEvent) => {
                if (event) {
                  this.offsetX = this.positionX + event.offsetX
                  this.offsetY = this.positionY + event.offsetY
                }
              })
              .onActionEnd(() => {
                this.positionX = this.offsetX
                this.positionY = this.offsetY
                console.info('Pan end')
              }),

            RotationGesture()
              .onActionUpdate((event: GestureEvent) => {
                if (event) {
                  this.angle = this.rotateValue + event.angle

                }
              })
              .onActionEnd((event: GestureEvent) => {
                this.rotateValue = this.angle
                console.error(`${json.stringify(event)}`)
                console.error(`${this.rotateValue}`)
                console.info('Rotation end')
              })
          )
          )
      }.width(500).height(500)

    }
  }
}
Enter fullscreen mode Exit fullscreen mode

To avoid this, place the combined gesture in the parent component:

import json from '@ohos.util.json'

@Entry
@Component
struct Index {
  @State imageWidth: number = 0
  @State imageHeight: number = 0
  @State offsetX: number = 0
  @State offsetY: number = 0
  @State positionX: number = 0
  @State positionY: number = 0
  @State angle: number = 0
  @State rotateValue: number = 0
  @State scaleValue: number = 1
  @State pinchValue: number = 1
  @State pinchX: number = 0
  @State pinchY: number = 0
  @State centerX: number = 0
  @State centerY: number = 0

  aboutToAppear(): void {

  }

  build() {
    Column() {
      Text('Title Bar')
        .width('100%')
        .height(50)
        .textAlign(TextAlign.Center)

      Column() {
        Image($r('app.media.app_icon'))
          .width(200)
          .height(200)
          .scale({ x: this.scaleValue, y: this.scaleValue, z: 1 })
          .translate({ x: this.offsetX, y: this.offsetY })
          .rotate({
            angle: this.angle,
          })

      }.width(500).height(500)
      .gesture(GestureGroup(GestureMode.Parallel,
        PanGesture()
          .onActionUpdate((event: GestureEvent) => {
            if (event) {
              this.offsetX = this.positionX + event.offsetX
              this.offsetY = this.positionY + event.offsetY
            }
          })
          .onActionEnd(() => {
            this.positionX = this.offsetX
            this.positionY = this.offsetY
            console.info('Pan end')
          }),

        RotationGesture()
          .onActionUpdate((event: GestureEvent) => {
            if (event) {
              this.angle = this.rotateValue + event.angle

            }
          })
          .onActionEnd((event: GestureEvent) => {
            this.rotateValue = this.angle
            console.error(`${json.stringify(event)}`)
            console.error(`${this.rotateValue}`)
            console.info('Rotation end')
          })
      )
      )
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

2. HarmonyOS notificationManager issues?

When a user clicks a notification in the notification bar, they can jump to other pages or publish public events via wantagent. How to implement calling an interface upon notification click?

Trigger a public event on notification click and call the interface in the public event callback.

3. How to obtain windowStage in Ability.test.ets for HarmonyOS?

After updating DevEco Studio to 5.0, the testability testrunner in the ohosTest directory of the project was removed. How to obtain windowStage in Ability.test.ets?

Refer to the following document: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-window-V5#windowstage9

WindowStage

Manages window instances as the window manager. The following API examples require calling corresponding methods using a WindowStage instance within the onWindowStageCreate() function.

getMainWindow

getMainWindow(callback: AsyncCallback<Window>): void

Asynchronously obtains the main window under the WindowStage instance via callback.

4. How to monitor foreground application switching in HarmonyOS?

Refer to the document: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-inner-application-applicationcontext-V5#applicationcontextontype-applicationstatechange-callback-applicationstatechangecallback10

ApplicationContext.on('abilityLifecycle')

on(type: 'abilityLifecycle', callback: AbilityLifecycleCallback): number

Registers to listen for in-application lifecycles with an asynchronous callback. Only callable from the main thread.

Example:

import { UIAbility, AbilityLifecycleCallback } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';


let lifecycleId: number;


export default class EntryAbility extends UIAbility {
  onCreate() {
    console.log('MyAbility onCreate');
    const abilityLifecycleCallback: AbilityLifecycleCallback = {
      onAbilityCreate(ability) {
        console.log(`AbilityLifecycleCallback onAbilityCreate ability: ${ability}`);
      },
      onWindowStageCreate(ability, windowStage) {
        console.log(`AbilityLifecycleCallback onWindowStageCreate ability: ${ability}`);
        console.log(`AbilityLifecycleCallback onWindowStageCreate windowStage: ${windowStage}`);
      },
      onWindowStageActive(ability, windowStage) {
        console.log(`AbilityLifecycleCallback onWindowStageActive ability: ${ability}`);
        console.log(`AbilityLifecycleCallback onWindowStageActive windowStage: ${windowStage}`);
      },
      onWindowStageInactive(ability, windowStage) {
        console.log(`AbilityLifecycleCallback onWindowStageInactive ability: ${ability}`);
        console.log(`AbilityLifecycleCallback onWindowStageInactive windowStage: ${windowStage}`);
      },
      onWindowStageDestroy(ability, windowStage) {
        console.log(`AbilityLifecycleCallback onWindowStageDestroy ability: ${ability}`);
        console.log(`AbilityLifecycleCallback onWindowStageDestroy windowStage: ${windowStage}`);
      },
      onAbilityDestroy(ability) {
        console.log(`AbilityLifecycleCallback onAbilityDestroy ability: ${ability}`);
      },
      onAbilityForeground(ability) {
        console.log(`AbilityLifecycleCallback onAbilityForeground ability: ${ability}`);
      },
      onAbilityBackground(ability) {
        console.log(`AbilityLifecycleCallback onAbilityBackground ability: ${ability}`);
      },
      onAbilityContinue(ability) {
        console.log(`AbilityLifecycleCallback onAbilityContinue ability: ${ability}`);
      }
    }
    // 1. Get applicationContext via the context property
    const applicationContext = this.context.getApplicationContext();
    try {
      // 2. Register to listen for in-application lifecycles via applicationContext
      lifecycleId = applicationContext.on('abilityLifecycle', abilityLifecycleCallback);
    } catch (paramError) {
      console.error(`error: ${(paramError as BusinessError).code}, ${(paramError as BusinessError).message}`);
    }
    console.log(`registerAbilityLifecycleCallback lifecycleId: ${lifecycleId}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

AbilityLifecycleCallback.onAbilityForeground

onAbilityForeground(ability: UIAbility): void

Triggers when the ability transitions from background to foreground after registering for lifecycle listening.

AbilityLifecycleCallback.onAbilityBackground

onAbilityBackground(ability: UIAbility): void

Triggers when the ability transitions from foreground to background after registering for lifecycle listening.

5. How to choose between performance when controlling component rendering via if condition or visibility in HarmonyOS?

Action Modes:

Developers can switch between component display and hiding states through if conditional rendering or visibility control. The difference in their action modes is as follows:

  • Conditional rendering via if: Creates the component when the condition is met and destroys it when not met.
    • The component is only created when the condition is satisfied.
    • When the condition is not met, the component is destroyed and not mounted in the component tree.
  • Visibility control: Controls component display or hiding based on parameter values.
    1. The component is created initially regardless of display status.
    2. When hidden, the component remains mounted in the component tree but is in an invisible state.

Scenario Selection:

  • Advantageous scenarios for visibility control:
    • When components have complex animations and need to switch frequently between display and hiding, use visibility control to avoid frequent creation and destruction, improving performance.
  • Advantageous scenarios for conditional rendering:
    • During cold start, if components do not need to be displayed initially, use conditional rendering to reduce rendering time and speed up startup.
    • If components have simple or no animations, do not switch frequently, or are mostly hidden, use conditional rendering to reduce interface complexity and nesting levels, improving performance.
    • If controlled components occupy large memory, prioritize conditional rendering to destroy unused components immediately and save memory.

Top comments (0)