使用PageView与Provider时触发PageController.page访问错误,求解决方案
解决PageView与Provider结合时的PageController.page访问错误
问题场景
在使用PageView组件和Provider状态管理实现分步注册页面时,触发以下断言错误:
Error: "PageController.page cannot be accessed before a PageView is built with it.
'package: flutter/src/widgets/page_view.dart':
Failed assertion: line 173 pos 7: 'positions.isNotEmpty'"
相关代码
RegistrationModel 状态模型
class RegistrationModel with ChangeNotifier { int _pageIndex; int _currentPage = 0; setCurrentPage(int value) { _currentPage = value; notifyListeners(); } }
注册页面组件
class RegistrationPagesView extends StatelessWidget { PageController pageController; RegistrationPagesView({this.pageController}); @override Widget build(BuildContext context) { return Consumer<RegistrationModel>( builder: (ctx, registrationModel, widget) { final pageView = PageView( onPageChanged: (value) { ctx.read<RegistrationModel>().setCurrentPage(value); }, controller: pageController, scrollDirection: Axis.horizontal, pageSnapping: true, physics: const NeverScrollableScrollPhysics(), children: [ FirstStepRegisterPage(), NewsPageRegistr(), MagazinePageRegistr(), RightPageRegistr(), ], ); if(registrationModel.currentPage != pageController.page.floor()) { pageController.jumpToPage(registrationModel.currentPage); } return pageView; }); } }
问题原因与修复方案
核心原因
错误源于PageView未完成构建、未与PageController绑定前,直接访问了pageController.page属性——此时PageController的positions列表为空,触发了Flutter内部的断言检查。
修复步骤
- 延迟页面跳转逻辑至Widget构建完成后
使用addPostFrameCallback确保在Widget树渲染完成后再执行页面跳转判断,避免提前访问未初始化的pageController.page:
class RegistrationPagesView extends StatelessWidget { final PageController pageController; RegistrationPagesView({required this.pageController}); @override Widget build(BuildContext context) { return Consumer<RegistrationModel>( builder: (ctx, registrationModel, widget) { // 帧后回调:确保PageView已绑定PageController WidgetsBinding.instance.addPostFrameCallback((_) { // 增加空安全判断,避免page为null时出错 if (registrationModel.currentPage != pageController.page?.floor()) { pageController.jumpToPage(registrationModel.currentPage); } }); return PageView( onPageChanged: (value) { ctx.read<RegistrationModel>().setCurrentPage(value); }, controller: pageController, scrollDirection: Axis.horizontal, pageSnapping: true, physics: const NeverScrollableScrollPhysics(), children: const [ FirstStepRegisterPage(), NewsPageRegistr(), MagazinePageRegistr(), RightPageRegistr(), ], ); }, ); } }
- 补充状态模型的getter方法
原模型缺少currentPage的读取方法,导致无法正确获取状态值,需补充:
class RegistrationModel with ChangeNotifier { int _currentPage = 0; // 补充currentPage的getter int get currentPage => _currentPage; setCurrentPage(int value) { // 避免重复触发通知优化性能 if (_currentPage != value) { _currentPage = value; notifyListeners(); } } }
- 初始化时同步PageController与状态模型
在父组件创建PageController时,直接同步状态模型的初始页面,减少首次渲染的跳转操作:
// 父组件中初始化PageController final registrationModel = Provider.of<RegistrationModel>(context, listen: false); final pageController = PageController(initialPage: registrationModel.currentPage);
内容的提问来源于stack exchange,提问作者Kouki
相关产品推荐
相关产品推荐

