How to solve the problem of the Progress component not responding when using animateTo to create a looping animation ?
Problem Description
Using the Progress component with animateTo to achieve a looping animation for the progress bar results in the animation not working and being unresponsive.
/** Minimum value of the progress bar */
const PROGRESS_MIN = 0
/** Maximum progress bar value */
const PROGRESS_MAX = 100
@Entry
@Component
struct ProgressAnim {
/** Current value of the progress bar */
@State progressValue: number = PROGRESS_MIN
uiContext: UIContext | undefined = undefined;
aboutToAppear() {
this.uiContext = this.getUIContext();
if (!this.uiContext) {
console.warn("no uiContext");
return;
}
}
build() {
Column({ space: 15 }) {
Progress({
value: this.progressValue, // Current progress value of the progress bar
total: PROGRESS_MAX, // Total length of the progress bar
type: ProgressType.Ring, // Progress bar types include Linear (linear style), ScaleRing (ring with scale style), Ring (ring without scale style), Eclipse (circular style), and Capsule (capsule style).
})
.style({
strokeWidth: 10, // Progress bar width, default is 4vp.
enableSmoothEffect: true // Switch for enabling or disabling the smooth progress effect. When the smooth effect is enabled, the progress will gradually transition from the current value to the set value; otherwise, it will abruptly change from the current value to the set value. Default value: true.
})
.width(100) // Progress bar component width
.color('# A97CF9') // Progress bar foreground color
.backgroundColor(Color.White) // Progress bar background color
Button('Start Animation')
.onClick(() => {
this.uiContext?.animateTo({
duration: 2000,
iterations: -1, // Setting -1 indicates that the animation loops indefinitely.
}, () => {
this.progressValue = PROGRESS_MAX
})
})
}
.width('100%')
.padding({ top: 5 })
.backgroundColor(Color.Gray)
}
}
Background Knowledge
- Progress: Displays loading/operation progress; styles include Capsule, Ring (with/without ticks), Circle, and custom shapes.
-
Explicit animation (
animateTo): Inserts transition effects for state changes of component properties (e.g., size, color). Content values that are not animated properties (like a progress value that the component doesn’t animate viaanimateTo) jump to the final state. -
Timer:
setInterval()repeatedly invokes a function at fixed intervals and returns an ID that must be cleared withclearInterval().
Troubleshooting Process
- Implemented a
Progress(Ring) and updated itsvalueinsideuiContext.animateTo({...}, () => { this.progressValue = 100 })withiterations: -1. - Observed that the progress animates from 0 → 100 only once; it does not loop as expected.
- Reasoned that
animateTotargets view property transitions, not repeatedly driving theProgressvalue. - Replaced
animateTowith a timer-driven approach: usesetInterval()to incrementprogressValueperiodically and reset when reaching the maximum.
Analysis Conclusion
animateTo is suitable for component property transitions (e.g., size/opacity/color), not for looping a Progress value. A timer is required to continuously update the value.
Solution
Use setInterval() to drive progressValue from PROGRESS_MIN to PROGRESS_MAX and wrap around, producing a smooth, continuous loop (optionally enable enableSmoothEffect for eased transitions inside the Progress itself).
Verification Result
- With the timer-based approach, the
Progressanimates smoothly and loops indefinitely. - The “Start” button has no effect if the loop is already running; “Stop” halts the loop and resets to the minimum.
Related Documents or Links
- Progress component guide (HarmonyOS/ArkTS):
-
UIContext.animateToAPI:
https://developer.huawei.com/consumer/en/doc/harmonyos-references/development-intro-api
- Timer APIs (
setInterval,clearInterval):
https://developer.huawei.com/consumer/en/doc/harmonyos-references/js-apis-timer#setinterval

Top comments (0)