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 });
}
}
Key Takeaways
-
animateTodoes not support intermediate UI updates during looped animations. - Use
keyframeAnimateToto define multiple animation segments with state updates. - Recursively trigger the animation in
onFinishto simulate looping while maintaining UI responsiveness. - This approach avoids redundant animation creation and ensures accurate state tracking.
Top comments (0)