DEV Community

HarmonyOS
HarmonyOS

Posted on

UI Not Updating During animateTo Loop Animation

Read the original article:UI Not Updating During animateTo Loop Animation

Context

When using animateTo to loop an animation in HarmonyOS, developers may attempt to update a state variable (e.g., incrementing a counter) during each animation cycle. However, the UI fails to reflect these updates in real time. Even though the animation is configured to loop three times, the UI only shows the counter increment once.

Description

The issue arises when using UIContext.animateTo() with the iterations parameter set to loop the animation. Although the state variable changeNum is incremented inside the animation’s closure, the UI does not re-render during each iteration. The onFinish callback confirms that changeNum remains at 1, indicating that intermediate updates are not reflected.

This behavior is due to how animateTo batches state changes and applies them only once at the end of the animation loop. Creating multiple animations manually could force updates but introduces redundancy and poor performance.

Solution

To resolve this, use keyframeAnimateTo instead of animateTo. This approach allows defining multiple animation segments (keyframes), each with its own duration and state update logic. By recursively triggering the animation in the onFinish callback, you can simulate looping while ensuring the UI updates correctly.

Working Example:

@Entry
@Component
struct AnimateToExample {
  @State widthSize: number = 250;
  @State heightSize: number = 100;
  @State rotateAngle: number = 0;
  uiContext: UIContext | undefined = undefined;
  @State changeNum: number = 0;

  aboutToAppear() {
    this.uiContext = this.getUIContext();
    if (!this.uiContext) {
      console.warn('no uiContext');
      return;
    }
  }

  playLrc() {
    this.uiContext?.keyframeAnimateTo({
      iterations: 1,
      onFinish: () => {
        if (this.changeNum % 3 !== 0) {
          this.playLrc(); // Recursively play animation 3 times
        }
      }
    }, [
      {
        duration: 800,
        event: () => {
          this.widthSize = 300;
          this.heightSize = 60;
          this.changeNum++; // UI updates here
        }
      },
      {
        duration: 500,
        event: () => {
          this.widthSize = 250;
          this.heightSize = 100;
        }
      }
    ]);
  }

  build() {
    Column() {
      Button(this.changeNum.toString())
        .width(this.widthSize)
        .height(this.heightSize)
        .margin(30)
        .onClick(() => {
          this.playLrc();
        });
    }.width('100%').margin({ top: 5 });
  }
}
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • animateTo does not support intermediate UI updates during looped animations.
  • Use keyframeAnimateTo to define multiple animation segments with state updates.
  • Recursively trigger the animation in onFinish to simulate looping while maintaining UI responsiveness.
  • This approach avoids redundant animation creation and ensures accurate state tracking.

Written by Emincan Ozcan

Top comments (0)