颤振中带有 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);
  }

现在动画可以正常工作了。