颤振中带有 AnimatedBuilder 的多个控制器
Multiple controllers with AnimatedBuilder in flutter
我正在寻找一种在 Flutter 中组合重复动画和非重复动画的方法。例如,开始播放动画(不是重复的),然后显示一些重复的动画,比如弹跳动画。目前,我在一个小部件上使用了 2 个动画控制器和 2 个动画生成器。这是我的示例代码:
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _outerAnimationController, //starting animation, not repetitive
builder: (context, _) {
return AnimatedBuilder(
animation: _innerCurvedAnimation, //repetitive animation, bouncing
builder: (context, _) {
return CustomPaint(
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: ShowCasePainter(
centerPosition: Offset(
MediaQuery.of(context).size.width / 2,
MediaQuery.of(context).size.height / 2),
innerCircleRadius: widget.innerCircleRadius +
(_innerCurvedAnimation.value * PaddingSmall), //repetitive animation value, bouncing
outerCircleRadius: _outerAnimationTween.value, //starting animation value, not repetitive
),
);
});
});
}
以这种方式使用多个控制器是一种好的做法吗?如何从代表不同动画的两个控制器影响 animatedBuilder?
感谢您的帮助!
在@pskink 的帮助下,我终于找到了解决方案。这里不需要使用多个 AnimatedBuilder,Listenable.merge 多个 AnimationControllers 就足够了。合并是可能的,因为 AnimationControllers 从 Listenable class 扩展而来。这是正确的代码:
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: Listenable.merge(
[_innerAnimationController, _outerAnimationController]),
builder: (context, _) {
return CustomPaint(
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: ShowCasePainter(
centerPosition: Offset(MediaQuery.of(context).size.width / 2,
MediaQuery.of(context).size.height / 2),
innerCircleRadius: widget.innerCircleRadius +
(_innerCurvedAnimation.value * PaddingSmall),
outerCircleRadius: _outerAnimationTween.value,
),
);
});
}
此解决方案适用于任何小部件,但使用 CustomPainter 有更好的解决方案。在 Custom painter 的情况下,animationControllers 可以通过构造函数传递到 CustomPainter 中,并且应该合并 class 内部。
父构建方法:
@override
Widget build(BuildContext context) {
return CustomPaint(
willChange: true,
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: ShowCasePainter(
centerPosition: Offset(MediaQuery.of(context).size.width / 2,
MediaQuery.of(context).size.height / 2),
innerCircleRadius: widget.innerCircleRadius,
outerCircleRadius: widget.outerCircleRadius,
innerAnimationController: _innerAnimationController,
outerAnimationController: _outerAnimationController,
),
);
}
如您所见,我只传递了不可变值,而不是使用 controllers/animations 中的值。
这是 CustomPainter 构造函数:
class ShowCasePainter extends CustomPainter {
final Offset centerPosition;
final double innerCircleRadius;
final double outerCircleRadius;
final Color backgroundColor;
final Color ringColor;
final Animation<double> innerAnimationController;
final Animation<double> outerAnimationController;
Animation<double> _innerCurvedAnimation;
Animation<double> _outerAnimationTween;
Animation<Color> _backgroudColorTween;
ShowCasePainter(
{this.innerAnimationController,
this.outerAnimationController,
this.centerPosition,
this.innerCircleRadius = 32.0,
this.outerCircleRadius = 128.0,
this.backgroundColor,
this.ringColor})
: super(
repaint: Listenable.merge(
[innerAnimationController, outerAnimationController])) {
_innerCurvedAnimation =
CurvedAnimation(parent: innerAnimationController, curve: Curves.easeIn);
_outerAnimationTween =
Tween(begin: innerCircleRadius, end: outerCircleRadius)
.animate(outerAnimationController);
_backgroudColorTween = ColorTween(
begin: Colors.transparent,
end: backgroundColor ?? Colors.black.withOpacity(0.2))
.animate(outerAnimationController);
}
现在动画可以正常工作了。
我正在寻找一种在 Flutter 中组合重复动画和非重复动画的方法。例如,开始播放动画(不是重复的),然后显示一些重复的动画,比如弹跳动画。目前,我在一个小部件上使用了 2 个动画控制器和 2 个动画生成器。这是我的示例代码:
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _outerAnimationController, //starting animation, not repetitive
builder: (context, _) {
return AnimatedBuilder(
animation: _innerCurvedAnimation, //repetitive animation, bouncing
builder: (context, _) {
return CustomPaint(
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: ShowCasePainter(
centerPosition: Offset(
MediaQuery.of(context).size.width / 2,
MediaQuery.of(context).size.height / 2),
innerCircleRadius: widget.innerCircleRadius +
(_innerCurvedAnimation.value * PaddingSmall), //repetitive animation value, bouncing
outerCircleRadius: _outerAnimationTween.value, //starting animation value, not repetitive
),
);
});
});
}
以这种方式使用多个控制器是一种好的做法吗?如何从代表不同动画的两个控制器影响 animatedBuilder?
感谢您的帮助!
在@pskink 的帮助下,我终于找到了解决方案。这里不需要使用多个 AnimatedBuilder,Listenable.merge 多个 AnimationControllers 就足够了。合并是可能的,因为 AnimationControllers 从 Listenable class 扩展而来。这是正确的代码:
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: Listenable.merge(
[_innerAnimationController, _outerAnimationController]),
builder: (context, _) {
return CustomPaint(
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: ShowCasePainter(
centerPosition: Offset(MediaQuery.of(context).size.width / 2,
MediaQuery.of(context).size.height / 2),
innerCircleRadius: widget.innerCircleRadius +
(_innerCurvedAnimation.value * PaddingSmall),
outerCircleRadius: _outerAnimationTween.value,
),
);
});
}
此解决方案适用于任何小部件,但使用 CustomPainter 有更好的解决方案。在 Custom painter 的情况下,animationControllers 可以通过构造函数传递到 CustomPainter 中,并且应该合并 class 内部。 父构建方法:
@override
Widget build(BuildContext context) {
return CustomPaint(
willChange: true,
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: ShowCasePainter(
centerPosition: Offset(MediaQuery.of(context).size.width / 2,
MediaQuery.of(context).size.height / 2),
innerCircleRadius: widget.innerCircleRadius,
outerCircleRadius: widget.outerCircleRadius,
innerAnimationController: _innerAnimationController,
outerAnimationController: _outerAnimationController,
),
);
}
如您所见,我只传递了不可变值,而不是使用 controllers/animations 中的值。 这是 CustomPainter 构造函数:
class ShowCasePainter extends CustomPainter {
final Offset centerPosition;
final double innerCircleRadius;
final double outerCircleRadius;
final Color backgroundColor;
final Color ringColor;
final Animation<double> innerAnimationController;
final Animation<double> outerAnimationController;
Animation<double> _innerCurvedAnimation;
Animation<double> _outerAnimationTween;
Animation<Color> _backgroudColorTween;
ShowCasePainter(
{this.innerAnimationController,
this.outerAnimationController,
this.centerPosition,
this.innerCircleRadius = 32.0,
this.outerCircleRadius = 128.0,
this.backgroundColor,
this.ringColor})
: super(
repaint: Listenable.merge(
[innerAnimationController, outerAnimationController])) {
_innerCurvedAnimation =
CurvedAnimation(parent: innerAnimationController, curve: Curves.easeIn);
_outerAnimationTween =
Tween(begin: innerCircleRadius, end: outerCircleRadius)
.animate(outerAnimationController);
_backgroudColorTween = ColorTween(
begin: Colors.transparent,
end: backgroundColor ?? Colors.black.withOpacity(0.2))
.animate(outerAnimationController);
}
现在动画可以正常工作了。