使用PageController实现页面动画,跳转返回后触发错误问题排查
问题描述
使用PageController实现页面动画效果,跳转至下一页后返回原页面时,触发PageController相关断言错误,错误信息如下:
Error: Assertion failed: file:///Users/vannak/Documents/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart:108:12 dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49 throw_ dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 29:3 assertFailed packages/flutter/src/widgets/scroll_controller.dart 108:33 get position packages/flutter/src/widgets/page_view.dart 196:41 animateToPage packages/rentkhapp/src/modules/map_module/map_property/controller/property_map_controller.dart 416:35 <fn> dart-sdk/lib/async/future.dart 424:39 <fn> dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19 internalCallback Another exception was thrown: [object Event]
问题原因
该断言错误的核心是:调用animateToPage时,PageController未关联任何有效的ScrollPosition(即对应的PageView已被销毁,或页面重建后控制器尚未完成绑定)。返回原页面后,若立刻执行动画逻辑,PageView可能还未完成渲染初始化,导致控制器状态异常。
解决方案
1. 规范PageController生命周期管理
确保控制器在页面初始化时创建,销毁时释放,避免内存泄漏和状态混乱:
late PageController _pageController; @override void initState() { super.initState(); _pageController = PageController(); } @override void dispose() { _pageController.dispose(); super.dispose(); }
2. 调用动画前检查控制器状态
在执行animateToPage前,必须通过hasClients判断控制器是否已绑定有效的PageView:
void triggerPageAnimation(int targetPage) { if (_pageController.hasClients) { _pageController.animateToPage( targetPage, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } }
3. 延迟执行动画(针对页面重建场景)
返回原页面后,若需要立刻触发动画,可通过addPostFrameCallback等待PageView完成渲染后再执行:
void triggerPageAnimationAfterBuild(int targetPage) { WidgetsBinding.instance.addPostFrameCallback((_) { if (_pageController.hasClients) { _pageController.animateToPage( targetPage, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } }); }
4. 保留页面状态(可选)
如果原页面在跳转后会被销毁重建,可通过AutomaticKeepAliveClientMixin保留页面状态,避免控制器重复初始化:
class _YourPageState extends State<YourPage> with AutomaticKeepAliveClientMixin { late PageController _pageController; @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { super.build(context); // 必须调用super方法 return PageView( controller: _pageController, // ...其他配置 ); } }
内容的提问来源于stack exchange,提问作者Van Nak
相关产品推荐
相关产品推荐

