AnimationController 是Flutter中动画的大本营。你可以用它来前进、倒退或重复动画,以及更多。
但是设置一个AnimationController ,需要很多的仪式。
// 1. declare a StatefulWidget
class RotatingContainer extends StatefulWidget {
@override
_RotatingContainerState createState() => _RotatingContainerState();
}
class _RotatingContainerState extends State<RotatingContainer>
// 2. add SingleTickerProviderStateMixin
with SingleTickerProviderStateMixin {
// 3. declare the animation controller
late final AnimationController _animationController;
@override
void initState() {
super.initState();
// 4. initialize the animation controller
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 750),
);
}
@override
void dispose() {
// 5. dispose when done
_animationController.dispose();
super.dispose();
}
// build method, etc.
}
这都是在我们写任何动画代码之前。如果我们想用它来显示一个旋转的盒子,我们可以在initState() 里面调用_animationController.repeat(); ,并在build() 方法中加入这段代码。
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animationController,
child: Container(color: Colors.red),
builder: (context, child) {
return Transform(
alignment: Alignment.center,
transform: Matrix4.rotationZ(2 * pi * _animationController.value),
child: child,
);
},
);
}
注意:红色的
Container是作为一个子节点传递给AnimatedBuilder,并在构建器内重复使用。参见"为什么TweenAnimationBuilder和AnimatedBuilder有一个子参数?"以获得对这种技术的解释。
如果你有很多明确的动画,就很难重用initState() 和dispose() 中的代码,而且在各部件之间复制粘贴所有的模板也容易出错。
因此,让我们来探索两种减少模板代码的方法。
[
赞助
Andrea的代码对每个人都是免费的。帮助我保持这种方式,看看这个赞助商。

**面向Flutter开发者的开源后端服务器。**Appwrite是一个安全的、自我托管的解决方案,它为开发者提供了一套易于使用的REST API来管理他们的核心后台需求。你可以用Appwrite构建任何东西点击这里了解更多。
1.使用 Flutter 钩子
该 flutter_hooks包使与AnimationController 的工作变得非常简单。
// Note: we are extending `HookWidget`
class RotatingContainer extends HookWidget {
@override
Widget build(BuildContext context) {
// All the steps above are replaced by a single line:
final controller = useAnimationController(duration: Duration(seconds: 2))
..repeat(); // start the animation
return AnimatedBuilder(
animation: controller,
child: Container(color: Colors.red),
builder: (context, child) {
return Transform(
alignment: Alignment.center,
transform: Matrix4.rotationZ(2 * pi * controller.value),
child: child,
);
},
);
}
}
所有获取TickerProvider 、初始化和处置AnimationController 的魔法都发生在 useAnimationController()方法。
Flutter 钩子是这种用例的一个很好的解决方案。如果您已经在您的项目中使用了它们,这就不难理解了。👍
但如果您不想让flutter_hooks成为一个额外的依赖项(例如因为您正在编写一个包),还有其他方法来减少模板代码。
2.扩展State类
你可以创建一个AnimationControllerState 的子类State<T> 来包含所有的AnimationController 逻辑。
import 'package:flutter/material.dart';
abstract class AnimationControllerState<T extends StatefulWidget>
extends State<T> with SingleTickerProviderStateMixin {
AnimationControllerState(this.animationDuration);
final Duration animationDuration;
late final animationController = AnimationController(
vsync: this,
duration: animationDuration
);
@override
void dispose() {
animationController.dispose();
super.dispose();
}
}
这里是原来的例子,更新后使用了这个。
class RotatingContainer extends StatefulWidget {
@override
_RotatingContainerState createState() =>
_RotatingContainerState(Duration(seconds: 2));
}
class _RotatingContainerState
extends AnimationControllerState<RotatingContainer> {
// add a constructor so we can pass the duration to the parent class
_RotatingContainerState(Duration duration) : super(duration);
// TODO: initState & build methods
}
在这种情况下,我们仍然需要一个StatefulWidget 。但所有的初始化和处置逻辑都在AnimationControllerState ,它现在是_RotatingContainerState 的父类。
我们可以像这样完成这个例子。
@override
void initState() {
super.initState();
// animationController is defined in the parent class, so we can use it here
animationController.repeat();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animationController,
child: Container(color: Colors.red),
builder: (context, child) {
return Transform(
alignment: Alignment.center,
transform: Matrix4.rotationZ(2 * pi * animationController.value),
child: child,
);
},
);
}
这比flutter_hooks的方法多了一点代码,但我们不需要额外的包依赖。
如果你不介意为你应用中的每个显式动画创建一个StatefulWidget ,这是一个很好的解决方案。许多需要显式动画的用例都需要一些状态变量,所以我觉得这在实践中可以接受。
useAnimationController()只是你可以使用的众多钩子中的一个。您可以使用flutter_hooks来管理状态和更多。请确保了解各种钩子以充分利用这个包。
差点忘了,这是上面的例子中正在运行的应用程序。
使用AnimationController旋转方形
总结
我们已经探索了两种方法来减少AnimationController boilerplate。
- 使用flutter_hooks包中的
useAnimationController() - 实现
AnimationControllerState并在需要时重复使用它
现在轮到您了
您准备好从您的Flutter 应用程序中删除大量不必要的代码了吗?
- 在整个项目中搜索
AnimationController - 用您喜欢的方法(
useAnimationController()或AnimationControllerState)替换所有的模板代码 - 测试一切,做一个PR,看看你节省了多少代码
不客气!😀