Flutter:如何在CustomPainter子类构造函数创建变量并传递给super
如何在CustomPainter内部管理Listenable以触发异步加载后的重绘
解决方案:使用工厂构造函数+私有构造函数
你可以通过工厂构造函数先创建ChangeNotifier实例,再将其传递给私有构造函数,同时完成super构造的传参和实例变量的存储。这样既符合Dart的构造函数规则,又能在类内部管理重绘触发逻辑。
完整代码示例:
import 'package:flutter/material.dart'; import 'dart:ui' as ui; class FadePainter extends CustomPainter { final ChangeNotifier _repaintNotifier; ui.Shader? _shader; // 私有构造函数:接收ChangeNotifier并传给super FadePainter._(this._repaintNotifier) : super(repaint: _repaintNotifier); // 工厂构造函数:对外暴露的构造入口 factory FadePainter() { final notifier = ChangeNotifier(); final painter = FadePainter._(notifier); // 触发异步加载shader painter._loadShader(); return painter; } Future<void> _loadShader() async { // 模拟异步加载shader的过程 await Future.delayed(const Duration(milliseconds: 500)); // 实际场景中替换为加载GLSL shader的逻辑 final shader = ui.Gradient.linear( const Offset(0, 0), const Offset(200, 200), [Colors.red, Colors.blue], ); _shader = shader; // 加载完成后触发重绘 _repaintNotifier.notifyListeners(); } @override void paint(Canvas canvas, Size size) { if (_shader == null) { // shader未加载时的占位绘制(可选) canvas.drawRect( Rect.fromLTWH(0, 0, size.width, size.height), Paint()..color = Colors.grey[200]!, ); return; } // 使用加载完成的shader绘制 canvas.drawRect( Rect.fromLTWH(0, 0, size.width, size.height), Paint()..shader = _shader, ); } @override bool shouldRepaint(covariant FadePainter oldDelegate) { // 因为我们通过repaint参数触发重绘,这里返回false即可 return false; } }
为什么这个方案可行?
- 工厂构造函数允许我们在创建实例前先初始化
ChangeNotifier,避免了直接在初始化列表中引用未初始化实例变量的问题。 - 私有构造函数确保只有工厂构造能创建实例,同时将
ChangeNotifier传递给super的repaint参数,满足CustomPainter的重绘监听需求。 - 所有异步加载和重绘触发逻辑都封装在类内部,不需要外部传入任何额外参数,也无需继承
ChangeNotifier增加冗余代码。
补充说明
- 如果需要处理shader加载失败的情况,可以在
_loadShader中添加异常捕获,并根据状态调整绘制逻辑。 - 若要优化性能,可以考虑使用
ValueNotifier替代ChangeNotifier,但对于简单的重绘触发场景,ChangeNotifier足够使用。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

