-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
Pull-Request has been made here
Use case
Currently, CircularProgressIndicator does not support passing an AnimationController, making it difficult to customize its animation behavior. Adding this capability would allow developers to have more fine-grained control over animation timing, easing, and synchronization with other animations.
-
Custom easing and timing for progress animations
-
Ability to pause, reverse, or manipulate the progress animation dynamically
-
Synchronization with other animations in an application:
Ensuring multiple CircularProgressIndicator widgets share the same animation, even if inserted at different times in the widget tree
Screen.Recording.2025-09-15.at.3.32.37.PM.mp4
Credit to @dkwingsmt for creating this preview
Proposal
Introduce a controller parameter that accepts an AnimationController, similar to how other widgets support animated behaviors. If provided, the CircularProgressIndicator should use this controller instead of the default built-in animation.
Steps to fix this:
- Add a nullable AnimationController to the class
CircularProgressIndicator
final AnimationController? controller;- In
_CircularProgressIndicatorStateadd a prop:
late final AnimationController _fallbackController;- In
initStatein_CircularProgressIndicatorState
Set
@override
void initState() {
super.initState();
_fallbackController = AnimationController(duration: const Duration(milliseconds: _kIndeterminateCircularDuration), vsync: this);
_controller = widget.controller ?? _fallbackController;
if (widget.value == null) {
_controller.repeat();
}
}- Set didUpdateWidget(...) to:
@override
void didUpdateWidget(CircularProgressIndicator oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller && _controller != widget.controller) {
if (oldWidget.controller == null) _controller.dispose();
_controller = widget.controller ?? _fallbackController;
}
if (widget.value == null && !_controller.isAnimating) {
_controller.repeat();
} else if (widget.value != null && _controller.isAnimating) {
_controller.stop();
}
}- In
disposeadd:
if (widget.controller == null) _controller.dispose();And there you have it: