Problem
I believe the docs are unclear about needing to dispose some animations and not others.
The docs refer to the following snippets as "alternative ways of expressing" the same thing.
-
final Animation<double> animation = _controller.drive(
CurveTween(curve: Curves.ease),
);
-
final Animation<double> animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
);
But from what I can see in the code,
_controller.drive creates an _AnimatedEvaluation object which proxies all listeners to its parent and doesn't hold any state of its own, and therefore doesn't need to be disposed. 👍🏽
CurvedAnimation adds an _updateCurveDirection listener to its parent and holds the direction as state. The user must dispose this object to remove that listener from its parent. 👎🏽
Additionally, one of the AnimationController examples shows users to call _controller.drive directly in the build method (paraphrased code snippet):
Widget build(BuildContext context) {
return SlideTransition(
position: controller.drive(
Tween(begin: Offset(0, 1), end: Offset.zero),
),
child: Text('...'),
);
}
This, with controller.drive, is fine.
But doing the same with CurvedAnimation leads to a new listener being added with each call of the build method, and it won't be removed.
Sure, they'll be freed when their AnimationController parent is disposed but in the meantime, it's a waste of memory.
Why this matters?
Writing controller.drive(Tween()) in the build method is a lot less verbose than creating a CurvedAnimation since we don't need to hold a reference in State.initState and dispose it in State.dispose.
And since people like writing less code, that's the way a lot of animations will be written.
We should anticipate this as a common pitfall and take reasonable steps not to tacitly encourage it.
Conversely, users may use the more verbose CurvedAnimation without knowing there's a nicer alternative. As an example, today I wrote 78 unnecessary lines of code (adil192/no_more_background@e71dc99) to dispose the CurvedAnimation in a flutter_hook, which I later found out could just be replaced with a single line (adil192/no_more_background@519aa59).
Initial thoughts/proposal:
I think the docs need to be more explicit about disposing these animations.
- The
CurvedAnimation docs should instruct us to call dispose on either the CurvedAnimation or its AnimationController parent when we're done. It should discourage creating CurvedAnimation as throwaway objects in e.g. a build method.
- The dartdoc for
CurvedAnimation.reverseCurve says "you might want to hold this object in a [State] object rather than recreating it each time your widget builds".
The latter should not be allowed or presented as an option here.
We should mention controller.drive(CurveTween()) as an alternative that doesn't need disposing.
- The
CurveTween doc provides a comparison between itself and CurvedAnimation. We can mention here that CurveAnimation needs disposing, while CurveTween does not.
I'm open to your thoughts, hence the issue and not a PR. I haven't profiled this so I don't know the real-world impact. But it could have saved me some time if the docs mentioned this. I also could be wrong about controller.drive not needing disposing.
flutter doctor -v (Flutter 3.41.4)
ahann@dellpro:~$ flutter doctor -v
[✓] Flutter (Channel stable, 3.41.4, on Fedora Linux 43 (COSMIC) 6.18.13-200.fc43.x86_64, locale en_GB.UTF-8)
[54ms]
• Flutter version 3.41.4 on channel stable at /home/ahann/Documents/Sources/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision ff37bef603 (2 days ago), 2026-03-03 16:03:22 -0800
• Engine revision e4b8dca3f1
• Dart version 3.11.1
• DevTools version 2.54.1
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop,
enable-android, enable-ios, cli-animations, enable-native-assets, omit-legacy-version-file,
enable-lldb-debugging, enable-uiscene-migration
[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0) [1,275ms]
• Android SDK at /home/ahann/Android/Sdk
• Emulator version 36.4.9.0 (build_id 14788078) (CL:N/A)
• Platform android-36, build-tools 36.1.0
• ANDROID_HOME = /home/ahann/Android/Sdk
• Java binary at: /home/ahann/.local/share/JetBrains/Toolbox/apps/android-studio/jbr/bin/java
This is the JDK bundled with the latest Android Studio installation on this machine.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 21.0.8+-14196175-b1038.72)
• All Android licenses accepted.
[✓] Chrome - develop for the web [7ms]
• CHROME_EXECUTABLE =
/home/ahann/.local/share/flatpak/app/org.chromium.Chromium/x86_64/stable/active/export/bin/org.chromium.Ch
romium
[✓] Linux toolchain - develop for Linux desktop [311ms]
• clang version 21.1.8 (Fedora 21.1.8-4.fc43)
• cmake version 3.31.10
• ninja version 1.13.1
• pkg-config version 2.3.0
• OpenGL core renderer: Mesa Intel(R) Graphics (LNL)
• OpenGL core version: 4.6 (Core Profile) Mesa 26.0.1
• OpenGL core shading language version: 4.60
• OpenGL ES renderer: Mesa Intel(R) Graphics (LNL)
• OpenGL ES version: OpenGL ES 3.2 Mesa 26.0.1
• OpenGL ES shading language version: OpenGL ES GLSL ES 3.20
• GL_EXT_framebuffer_blit: yes
• GL_EXT_texture_format_BGRA8888: yes
[✓] Connected device (2 available) [250ms]
• Linux (desktop) • linux • linux-x64 • Fedora Linux 43 (COSMIC) 6.18.13-200.fc43.x86_64
• Chrome (web) • chrome • web-javascript • Chromium 145.0.7632.159
[✓] Network resources [508ms]
• All expected network resources are available.
• No issues found!
ahann@dellpro:~$
Problem
I believe the docs are unclear about needing to dispose some animations and not others.
The docs refer to the following snippets as "alternative ways of expressing" the same thing.
But from what I can see in the code,
_controller.drivecreates an_AnimatedEvaluationobject which proxies all listeners to its parent and doesn't hold any state of its own, and therefore doesn't need to be disposed. 👍🏽CurvedAnimationadds an_updateCurveDirectionlistener to its parent and holds the direction as state. The user must dispose this object to remove that listener from its parent. 👎🏽Additionally, one of the AnimationController examples shows users to call
_controller.drivedirectly in the build method (paraphrased code snippet):This, with
controller.drive, is fine.But doing the same with
CurvedAnimationleads to a new listener being added with each call of thebuildmethod, and it won't be removed.Sure, they'll be freed when their AnimationController parent is disposed but in the meantime, it's a waste of memory.
Why this matters?
Writing
controller.drive(Tween())in the build method is a lot less verbose than creating a CurvedAnimation since we don't need to hold a reference in State.initState and dispose it in State.dispose.And since people like writing less code, that's the way a lot of animations will be written.
We should anticipate this as a common pitfall and take reasonable steps not to tacitly encourage it.
Conversely, users may use the more verbose CurvedAnimation without knowing there's a nicer alternative. As an example, today I wrote 78 unnecessary lines of code (adil192/no_more_background@e71dc99) to dispose the CurvedAnimation in a flutter_hook, which I later found out could just be replaced with a single line (adil192/no_more_background@519aa59).
Initial thoughts/proposal:
I think the docs need to be more explicit about disposing these animations.
CurvedAnimationdocs should instruct us to call dispose on either the CurvedAnimation or its AnimationController parent when we're done. It should discourage creatingCurvedAnimationas throwaway objects in e.g. a build method.CurvedAnimation.reverseCurvesays "you might want to hold this object in a [State] object rather than recreating it each time your widget builds".The latter should not be allowed or presented as an option here.
We should mention
controller.drive(CurveTween())as an alternative that doesn't need disposing.CurveTweendoc provides a comparison between itself andCurvedAnimation. We can mention here thatCurveAnimationneeds disposing, whileCurveTweendoes not.I'm open to your thoughts, hence the issue and not a PR. I haven't profiled this so I don't know the real-world impact. But it could have saved me some time if the docs mentioned this. I also could be wrong about
controller.drivenot needing disposing.flutter doctor -v (Flutter 3.41.4)