DEV Community

HarmonyOS
HarmonyOS

Posted on

Implement synchronized rotating image animation across pages

Read the original article:Implement synchronized rotating image animation across pages

Requirement Description

The core requirement is to implement synchronized rotation animation for an Image component across two separate pages by utilizing a shared global state to trigger and coordinate the animation update.

Background Knowledge

  • AppStorage: Is an application-level global UI state storage container, created by the UI framework upon application startup, used to store UI state data in runtime memory.
  • Image: Is the core component in the UI framework used for rendering images. It supports various formats and dynamic loading capabilities. The rotate attribute is a corresponding modifier property that rotates the image by a specified angle and supports dynamic binding to state values.

Implementation Steps

The synchronization of the Image component's rotation animation across two pages can be achieved using AppStorage global state management, specifically as follows:

  1. Share the startFlag state via AppStorage: Page 1 modifies the state using AppStorage.set(), and Page 2 reads the state using AppStorage.get().
  2. Bind the startFlag state using the @StorageProp('startFlag') decorator. When startFlag changes, the change() method is triggered to dynamically update the rotation angle and animation duration, thereby controlling the Image rotation animation.

Code Snippet / Configuration

// PageOne
@Entry
@Component
struct Index {
  @StorageProp('startFlag') @Watch('change') startFlag: boolean = false;
  @State rotateValue: number = 0;
  @State ifStop: number = -1;
  @State duration: number = 4000;

  change() {
    console.info(`startFlag: ${this.startFlag}`);
    if (this.startFlag) {
      this.duration = 4000;
      this.rotateValue = 360;
    } else {
      this.rotateValue = 0;
    }
  }

  build() {
    Column({ space: 30 }) {
      Button('Click')
        .onClick(() => {
          this.getUIContext().getRouter().pushUrl({
            url: 'pages/Index2',
            params: {
              flag: '1',
            }
          });
        });

      // The 'app.media.startIcon' here is only an example. Developers should replace it themselves, otherwise the imageSource creation failure will prevent subsequent execution.
      Image($r('app.media.startIcon'))
        .width(200)
        .aspectRatio(1)
        .borderRadius(100)
        .rotate({
          angle: this.rotateValue
        })
        .animation({
          duration: this.duration,
          iterations: -1, // Animation repetition count
          curve: Curve.Linear,
          delay: 1, // Delay time
          playMode: PlayMode.Normal
        });

      Button('Rotate').onClick(() => {
        this.duration = 4000;
        this.rotateValue = 360;
        AppStorage.set('startFlag', true);
      });

      Button('Stop').onClick(() => {
        this.duration = 0;
        this.rotateValue = 0;
        AppStorage.set('startFlag', false);
      });
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%');
  }
}
Enter fullscreen mode Exit fullscreen mode
// PageTwo
@Entry
@Component
struct Index2 {
  @State rotateValue: number = 0;
  @State duration: number = 4000;
  @State pauseFlag: boolean = false;

  onPageShow(): void {
    const startFlag = AppStorage.get('startFlag') as boolean;
    console.info(`Page Two: startFlag: ${startFlag}`);
    if (startFlag) {
      this.duration = 4000;
      this.rotateValue = 360;
    } else {
      this.duration = 0;
      this.rotateValue = 0;
    }
  }

  build() {
    Column({ space: 30 }) {
      // NOTE: The 'app.media.startIcon' image source must be replaced by the developer to ensure correct functionality.
      Image($r('app.media.startIcon'))
        .width(200)
        .aspectRatio(1)
        .borderRadius(100)
        .rotate({
          angle: this.rotateValue
        })
        .animation({
          duration: this.duration,
          iterations: -1, // Animation repetition count
          curve: Curve.Linear,
          delay: 1, // Delay time
          playMode: PlayMode.Normal
        });

      Button('Rotate').onClick(() => {
        this.duration = 4000;
        this.rotateValue = 360;
        AppStorage.set('startFlag', true);
      });

      Button('Stop').onClick(() => {
        this.duration = 0;
        this.rotateValue = 0;
        AppStorage.set('startFlag', false);
      });

      Button('Back').onClick(() => {
        this.getUIContext().getRouter().back({
          url: 'pages/Index',
          params: this.pauseFlag
        });
      });
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%');
  }
}
Enter fullscreen mode Exit fullscreen mode

Test Results

a.gif

Limitations or Considerations

  • This example supports API Version 20 Release and above.
  • This example supports HarmonyOS 6.0.0 Release SDK and above.
  • This example requires DevEco Studio 6.0.0 Release and above for compilation and execution.

Written by Muhammet Ali Ilgaz

Top comments (0)