为CupertinoPicker设置FixedExtentScrollController后页面切换报错
解决PageView切换后CupertinoPicker使用FixedExtentScrollController的断言错误
问题根源
当PageView切换到页面2时,未启用状态保持的页面1会被标记为不可见,其内部CupertinoPicker对应的RenderObject会被释放。但FixedExtentScrollController仍持有对该已释放RenderObject的监听,返回页面1操作Picker时,控制器发送滚动通知给已销毁的对象,触发!_debugDisposed断言错误。
解决方案
方法一:启用页面状态保持(推荐)
使用AutomaticKeepAliveClientMixin让页面1在切换时保持状态,避免RenderObject被释放,同时在State中正确管理控制器的生命周期。
class Page1 extends StatefulWidget { @override _Page1State createState() => _Page1State(); } class _Page1State extends State<Page1> with AutomaticKeepAliveClientMixin { final FixedExtentScrollController _scrollController = FixedExtentScrollController(); // 启用状态保持 @override bool get wantKeepAlive => true; @override void dispose() { // 页面销毁时释放控制器 _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // 必须调用super.build,否则状态保持不生效 super.build(context); return CupertinoPicker( scrollController: _scrollController, itemExtent: 50, onSelectedItemChanged: (index) { // 处理选中事件 }, children: List.generate(20, (index) => Center(child: Text('选项 $index'))), ); } }
方法二:重建控制器(适合不需要保留选中状态的场景)
如果不需要保留页面1的选中状态,可以在页面每次初始化时创建新的控制器,销毁时释放旧控制器,避免关联已释放的RenderObject。
class Page1 extends StatefulWidget { @override _Page1State createState() => _Page1State(); } class _Page1State extends State<Page1> { late FixedExtentScrollController _scrollController; @override void initState() { super.initState(); _scrollController = FixedExtentScrollController(); } @override void dispose() { _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return CupertinoPicker( scrollController: _scrollController, itemExtent: 50, onSelectedItemChanged: (index) {}, children: List.generate(20, (index) => Center(child: Text('选项 $index'))), ); } }
注意事项
- 控制器必须在页面的State中创建,禁止使用全局控制器,否则会导致跨页面的状态冲突。
- 使用状态保持时,确保
wantKeepAlive返回true且build方法中调用super.build(context)。
内容的提问来源于stack exchange,提问作者Nitneuq
相关产品推荐
相关产品推荐

