flutter-animating-apps by flutter/skills
npx skills add https://github.com/flutter/skills --skill flutter-animating-apps使用核心类型化的 Animation 系统来管理 Flutter 动画。不要手动计算帧;应依赖框架的 Ticker 和插值类。
Animation<T>:将其视为一个随时间变化的值的抽象表示。它持有状态(已完成、已取消)并通知监听器,但对 UI 一无所知。AnimationController:实例化此类以驱动动画。它生成与屏幕刷新率绑定的值(通常为 0.0 到 1.0)。始终提供一个 vsync(通常通过 SingleTickerProviderStateMixin)以防止离屏资源消耗。务必调用 dispose() 方法处理控制器以防止内存泄漏。广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
Tween<T>:定义一个从输入范围(通常为 0.0-1.0)到输出类型(例如 Color、Offset、double)的无状态映射。使用 .animate() 将补间与曲线链接起来。Curve:使用 CurvedAnimation 或 CurveTween 将非线性时序(例如 Curves.easeIn、Curves.bounceOut)应用于动画。应用条件逻辑来选择正确的动画方法:
AnimatedContainer、AnimatedOpacity、TweenAnimationBuilder)。AnimatedBuilder 或 AnimatedWidget 使用 AnimationController)。SpringSimulation)。Interval 曲线由单个 AnimationController 驱动的多个 Tween)。对于“一劳永逸”的状态驱动动画,使用此工作流程。
Container)替换为其对应的动画版本(例如 AnimatedContainer)。duration 属性。curve 属性。setState() 调用中更新属性来触发动画。当需要对动画生命周期进行精细控制时,使用此工作流程。
SingleTickerProviderStateMixin(或用于多个控制器的 TickerProviderStateMixin)添加到 State 类。initState() 中初始化一个 AnimationController,提供 vsync: this 和一个 duration。Tween 并使用 .animate() 将其链接到控制器。AnimatedBuilder 中(对于复杂树结构首选)或子类化 AnimatedWidget。Animation 对象传递给 AnimatedBuilder 的 animation 属性。controller.forward()、controller.reverse() 或 controller.repeat() 控制播放。dispose() 方法中调用 controller.dispose()。dispose()。使用此工作流程在两个路由之间“飞行”一个小部件。
Hero 小部件中。Hero 分配一个唯一的、数据驱动的 tag。Hero 小部件中。Hero 分配完全相同的 tag。Hero 小部件内的小部件树在视觉上相似,以防止突兀的跳跃。Navigator 推送目标路由来触发转场。对于手势驱动的自然运动,使用此工作流程。
AnimationController(不要设置固定的持续时间)。GestureDetector(例如 onPanEnd 提供 DragEndDetails)捕获手势速度。SpringSimulation。controller.animateWith(simulation) 驱动控制器。class StaggeredAnimationDemo extends StatefulWidget {
@override
State<StaggeredAnimationDemo> createState() => _StaggeredAnimationDemoState();
}
class _StaggeredAnimationDemoState extends State<StaggeredAnimationDemo> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _widthAnimation;
late Animation<Color?> _colorAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
// 交错宽度动画(0.0 到 0.5 区间)
_widthAnimation = Tween<double>(begin: 50.0, end: 200.0).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.5, curve: Curves.easeIn),
),
);
// 交错颜色动画(0.5 到 1.0 区间)
_colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.5, 1.0, curve: Curves.easeOut),
),
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose(); // 关键:防止内存泄漏
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Container(
width: _widthAnimation.value,
height: 50.0,
color: _colorAnimation.value,
);
},
);
}
}
Route createCustomRoute(Widget destination) {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => destination,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0); // 从底部开始
const end = Offset.zero;
const curve = Curves.easeOut;
final tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
final offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
);
}
// 用法:Navigator.of(context).push(createCustomRoute(const NextPage()));
每周安装量
2.0K
代码仓库
GitHub 星标数
784
首次出现
11 天前
安全审计
已安装于
codex2.0K
gemini-cli2.0K
opencode2.0K
github-copilot2.0K
kimi-cli2.0K
amp2.0K
Manage Flutter animations using the core typed Animation system. Do not manually calculate frames; rely on the framework's ticker and interpolation classes.
Animation<T>: Treat this as an abstract representation of a value that changes over time. It holds state (completed, dismissed) and notifies listeners, but knows nothing about the UI.AnimationController : Instantiate this to drive the animation. It generates values (typically 0.0 to 1.0) tied to the screen refresh rate. Always provide a vsync (usually via SingleTickerProviderStateMixin) to prevent offscreen resource consumption. Always dispose() controllers to prevent memory leaks.Tween<T>: Define a stateless mapping from an input range (usually 0.0-1.0) to an output type (e.g., Color, Offset, double). Chain tweens with curves using .animate().Curve : Apply non-linear timing (e.g., Curves.easeIn, Curves.bounceOut) to an animation using a CurvedAnimation or CurveTween.Apply conditional logic to select the correct animation approach:
AnimatedContainer, AnimatedOpacity, TweenAnimationBuilder).AnimationController with AnimatedBuilder or AnimatedWidget).SpringSimulation).Use this workflow for "fire-and-forget" state-driven animations.
Container) with its animated counterpart (e.g., AnimatedContainer).duration property.curve property for non-linear motion.setState() call.Use this workflow when you need granular control over the animation lifecycle.
SingleTickerProviderStateMixin (or TickerProviderStateMixin for multiple controllers) to the State class.AnimationController in initState(), providing vsync: this and a duration.Tween and chain it to the controller using .animate().AnimatedBuilder (preferred for complex trees) or subclass .Use this workflow to fly a widget between two routes.
Hero widget.tag to the source Hero.Hero widget.tag to the destination Hero.Hero widgets are visually similar to prevent jarring jumps.Navigator.Use this workflow for gesture-driven, natural motion.
AnimationController (do not set a fixed duration).GestureDetector (e.g., onPanEnd providing DragEndDetails).SpringSimulation with mass, stiffness, damping, and the calculated velocity.controller.animateWith(simulation).class StaggeredAnimationDemo extends StatefulWidget {
@override
State<StaggeredAnimationDemo> createState() => _StaggeredAnimationDemoState();
}
class _StaggeredAnimationDemoState extends State<StaggeredAnimationDemo> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _widthAnimation;
late Animation<Color?> _colorAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
// Staggered width animation (0.0 to 0.5 interval)
_widthAnimation = Tween<double>(begin: 50.0, end: 200.0).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.0, 0.5, curve: Curves.easeIn),
),
);
// Staggered color animation (0.5 to 1.0 interval)
_colorAnimation = ColorTween(begin: Colors.blue, end: Colors.red).animate(
CurvedAnimation(
parent: _controller,
curve: const Interval(0.5, 1.0, curve: Curves.easeOut),
),
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose(); // CRITICAL: Prevent memory leaks
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Container(
width: _widthAnimation.value,
height: 50.0,
color: _colorAnimation.value,
);
},
);
}
}
Route createCustomRoute(Widget destination) {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => destination,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0); // Start from bottom
const end = Offset.zero;
const curve = Curves.easeOut;
final tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
final offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
);
}
// Usage: Navigator.of(context).push(createCustomRoute(const NextPage()));
Weekly Installs
2.0K
Repository
GitHub Stars
784
First Seen
11 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex2.0K
gemini-cli2.0K
opencode2.0K
github-copilot2.0K
kimi-cli2.0K
amp2.0K
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
Tweens driven by a single AnimationController using Interval curves).AnimatedWidgetAnimation object to the AnimatedBuilder's animation property.controller.forward(), controller.reverse(), or controller.repeat().controller.dispose() in the dispose() method.dispose() is called.