如何按需配置controller?

How to dispose controller on demand?

编辑-:一个相关的问题也是如何动态处理多个控制器?

我有一个自定义画家,其中每个对象都需要单独设置动画。在一定时间后,数据被添加到列表中,我对其进行绘制并制作动画。

这是它的样子,

动画的模型class

class Wave {
  AnimationController animationController;
  Animation<double> animation;
  bool isDisposed;

  Wave({
    required this.animationController,
    required this.animation,
    this.isDisposed = false,
  });
}
@override
  void paint(Canvas canvas, Size size) {
for (var i = 0; i < waveData.length; i++) {
    addAnimatedWaves(i); // <------- a callback to add animation model to list
    animatedWaves[i].animationController.forward();
    canvas.drawLine(...);

   if (animatedWaves[i].animationController.status ==
            AnimationStatus.dismissed &&
    !animatedWaves[i].isDisposed) { //<------ trying to dispose but it won't get executed
      animatedWaves[i].animationController.dispose();
      animatedWaves[i].animation.removeListener(() {});
      animatedWaves[i].isDisposed = true;
    }
 }
}

这就是上面提到的回调,

 void addAnimatedWaves(int i) {
    if (_waves.isEmpty) {
      var controller = AnimationController(
          vsync: this, duration: const Duration(milliseconds: 500));
      _waves.add(Wave(
        animationController: controller,
        animation: Tween(begin: 0.0, end: 1.0).animate(
          CurvedAnimation(parent: controller, curve: Curves.easeIn),
        ),
      ));
    } else {
      if (_waves.length > i) {
        var controller = AnimationController(
            vsync: this, duration: const Duration(milliseconds: 500));
        _waves.add(Wave(
          animationController: controller,
          animation: Tween(begin: 0.0, end: 1.0).animate(
            CurvedAnimation(parent: controller, curve: Curves.easeIn),
          ),
        ));
      }
      _waves[i].animation.addListener(() {
        if (mounted) setState(() {});
      });
    }
  }

处置

@override
  void dispose() {
   for (var wave in _waves) { // it always calls every dispose method because every 
                                // controller is active
      if (!wave.isDisposed) {
        wave.animationController.dispose();
        wave.animation.removeListener(() {});
      }
    }
    super.dispose();
  }

我想要的是当动画完成时立即处理一个控制器。和 优化最后的 for 循环,使其没有整个列表的长度。

那么谁能建议应该做什么或者是否有更好的方法来为需要单独设置动画的对象列表设置动画?

好的,所以我找到了这个解决方案,如果有人有更好的解决方案,那么我很乐意更改已接受的答案。

首先,@pskink 建议我们不应该在 paints 中使用控制器,所以将它们移除并添加到 addAnimatedWave()

@override
  void paint(Canvas canvas, Size size) {
   if (animatedWaves.isEmpty) {
        addAnimatedWaves(i);//---->for first time
      } else {
       if (animatedWaves.isNotEmpty && i >= animatedWaves.length - 1) {
         addAnimatedWaves(i);
        }
      }
    canvas.drawLine(...);
}

以上条件检查索引是否包含任何值。 因此,如果它包含则不需要它并跳过它。

 void _addAnimatedWave(int i) {
    if (_waves.isEmpty) {
      _addWave(); // <--- it just creates new controller and adds to _waves
                  //you can refer it from question.
    } else {
      if (_waves.length > i) {
        _addWave();
      }
      _waves[i].animationController.forward();
      _waves[i].animation.addListener(() {
        if (mounted) setState(() {});
      });
      _waves[i].animationController.addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          _waves[i].animationController.dispose();
          _waves[i].animation.removeListener(() {});
          _waves[i].isDisposed = true;
        }
      });
    }
  }

这里我们为每个 AnimationController 添加一个侦听器,但它会一直激活,直到控制器的动画完成,我们会立即处理它。

所以对于我的情况,单个控制器将是 active for 300ms

之前它每隔 2-3 seconds 添加 1000+ 控制器,现在它只为每个波浪条添加一个控制器。

现在剩下的控制器仍然处于活动状态,而小部件已从小部件树中删除。

@override
  void dispose() {
    for (var i = _waves.length - 1; i >= 0; i--) {
      if (_waves[i].isDisposed) {
        break;
      }
      _waves[i].animationController.dispose();
      _waves[i].animation.removeListener(() {});
    }
    super.dispose();
  }

对于我来说,处置控制器是 linear 所以如果我们 reverse 列表并到达处置的 first 控制器,之后每个控制器都会被处置,所以我们不需要遍历整个列表,所以我们可以break那个循环。

通过这种优化,我注意到只有 max 3 个控制器需要用 for-loop 处理。