Flutter中AnimatedBuilder结合CustomPainter动画视图停止更新问题求助
我之前也踩过这个一模一样的坑!这种现象本质上是CustomPainter的重绘逻辑没有正确触发导致的,跟AnimatedBuilder本身无关。
问题原因分析
当你在AnimatedBuilder的builder里只返回CustomPaint时,Flutter会检查BarPainter的shouldRepaint方法来决定是否需要重绘。如果你的BarPainter没有正确实现这个方法(比如默认返回false,或者没有对比percent的变化),那么即使_animationController.value在持续变化,Flutter也会认为不需要重绘CustomPainter,所以视图就停住了。
而当你加入Text组件后,Text的内容会随着动画值实时变化,它自身会触发重绘,这会带动AnimatedBuilder重新执行builder方法——每次都会创建一个新的BarPainter实例,相当于强制触发了CustomPainter的重绘,所以动画看起来就正常了,但这其实是个“治标不治本”的临时方案。
正确的解决方案
修改你的BarPainter,正确实现shouldRepaint方法,对比新旧委托的percent(以及其他可能变化的属性,比如color),当值发生变化时返回true:
class BarPainter extends CustomPainter { final Color color; final double percent; BarPainter({required this.color, required this.percent}); @override void paint(Canvas canvas, Size size) { // 你的进度条绘制逻辑示例 final paint = Paint()..color = color; final barWidth = size.width * percent; canvas.drawRect(Rect.fromLTWH(0, 0, barWidth, size.height), paint); } @override bool shouldRepaint(covariant BarPainter oldDelegate) { // 只要percent或color变化,就触发重绘 return oldDelegate.percent != percent || oldDelegate.color != color; } }
这样修改后,即使AnimatedBuilder的builder里只返回CustomPaint,Flutter也会在_animationController.value变化时,通过shouldRepaint的判断触发CustomPainter的重绘,动画就能正常运行了。
更高效的进阶写法
另外,也可以让BarPainter直接监听动画对象,这样能避免AnimatedBuilder反复创建Painter实例,性能更优:
class BarPainter extends CustomPainter { final Color color; final Animation<double> animation; // 通过super传入repaint参数,让Painter直接监听动画变化 BarPainter({required this.color, required this.animation}) : super(repaint: animation); @override void paint(Canvas canvas, Size size) { final percent = animation.value; // 绘制逻辑... } @override bool shouldRepaint(covariant BarPainter oldDelegate) { // 只在color变化时才重绘,动画值变化由repaint参数处理 return oldDelegate.color != color; } }
使用时直接把动画对象传给Painter即可:
AnimatedBuilder( animation: _animationController, builder: (context, child) { return CustomPaint( painter: BarPainter( color: widget.color, animation: _animationController, ), ); }, );
内容的提问来源于stack exchange,提问作者Anthony

