从其他页面启动Flutter滑块拼图项目时出现两类异常问题
解决Flutter滑块拼图项目的两个启动异常
咱们来一步步拆解你遇到的这两个异常,从根源上解决问题:
1. Unsupported operation: Infinity or NaN toInt 异常
这个错误的栈跟踪指向了语义化节点的尺寸计算,说白了就是你的界面里某个Widget的尺寸算出了无限大或者非数值,转成整数的时候直接崩了。
从你贴的代码来看,可能的诱因有两个:
- 虽然你给
rows和columns设了默认值3,但如果外部传参时不小心传了0,后续计算拼图块尺寸时就会出现除以0的情况,直接产出NaN; - 拼图容器没有明确的尺寸约束,导致子Widget的尺寸计算溢出成Infinity。
修复步骤:
- 给行列数加个校验,确保永远大于0,在
PuzzlePage的构造函数里加断言:
PuzzlePage({int columns = 3, int rows = 3}) : columns = columns ?? 3, rows = rows ?? 3 { assert(columns > 0, "列数必须大于0"); assert(rows > 0, "行数必须大于0"); }
- 给拼图容器加明确的尺寸约束,比如用屏幕尺寸的80%作为拼图大小,避免无限尺寸:
// 在_PuzzleHome的build方法里添加约束 @override Widget build(BuildContext context) { final screenSize = MediaQuery.of(context).size; final puzzleSize = min(screenSize.width, screenSize.height) * 0.8; return Container( width: puzzleSize, height: puzzleSize, // 这里放你的拼图内容 ); }
2. NoSuchMethodError: The getter '_duration' was called on null 异常
这个错误很直白:你调用某个对象的_duration属性时,那个对象是null。结合你的代码,问题大概率出在PuzzleAnimator的初始化上。
你现在是在_PuzzleHome的createState里直接new了PuzzleAnimator并传给PuzzleHomeState,如果PuzzleAnimator的初始化依赖上下文或者需要异步操作,这种写法很容易导致实例初始化不完整,后续用的时候就成null了;另外,如果PuzzleHomeState没有正确持有这个实例,也可能被回收成null。
修复步骤:
- 把
PuzzleAnimator的初始化移到PuzzleHomeState的initState里,不要在createState里传:
class _PuzzleHome extends StatefulWidget { final int _rows, _columns; const _PuzzleHome(this._rows, _columns, {Key key}) : super(key: key); @override PuzzleHomeState createState() => PuzzleHomeState(); } class PuzzleHomeState extends State<_PuzzleHome> { PuzzleAnimator _animator; @override void initState() { super.initState(); // 在这里初始化动画器,确保上下文准备好 _animator = PuzzleAnimator(widget._columns, widget._rows); } // 后续使用_animator前可以加个判空,或者确保初始化完成 }
- 检查
PuzzleAnimator的实现,确保_duration在初始化时就被赋值,别搞延迟初始化导致null:
class PuzzleAnimator { final int columns; final int rows; Duration _duration; // 用初始化列表直接赋值 PuzzleAnimator(this.columns, this.rows) : _duration = Duration(milliseconds: 300); // 或者在构造函数里初始化 // PuzzleAnimator(this.columns, this.rows) { // _duration = Duration(milliseconds: 300); // } }
额外的代码小问题
- 你的
PuzzlePage里的_context变量没赋值,在didUpdateWidget里调用AppBuilder.of(_context)肯定会报错,记得在build方法里赋值:
@override Widget build(BuildContext context) { _context = context; // 在这里把上下文存起来 return AppBuilder( builder: (context) { return _PuzzleHome(widget.rows, widget.columns); }); }
WidgetsBindingObserver的注册漏了,在PuzzlePageState的initState里加上:
@override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); // 注册观察者 }
内容的提问来源于stack exchange,提问作者George John
相关产品推荐
相关产品推荐

