Flutter子树中获取PrimaryScrollController报错问题求助
在Flutter项目中,我已在MyTestingPage组件内创建ScrollController,并将其传入PrimaryScrollController的controller参数,同时将primary设为true的SingleChildScrollView作为其子组件。在独立文件的ChildWidget子组件中,尝试在按钮点击事件里通过PrimaryScrollController.of(context)获取该控制器,却触发错误。
错误信息:
Exception has occurred. FlutterError (PrimaryScrollController.of() was called with a context that does not contain a PrimaryScrollController widget. No PrimaryScrollController widget ancestor could be found starting from the context that was passed to PrimaryScrollController.of(). This can happen because you are using a widget that looks for a PrimaryScrollController ancestor, but no such ancestor exists. The context used was: ChildWidget(dependencies: [PrimaryScrollController])) !D/EGL_emulation
相关代码
主入口与MyApp
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await configureDependencies(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return BlocProvider( create: (context) => getIt<LocationControllBloc>(), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), home: MyTestingPage(), ), ); } }
MyTestingPage组件
class MyTestingPage extends StatelessWidget { MyTestingPage({super.key}); final controller = ScrollController(); @override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: const EdgeInsets.all(2.0), child: PrimaryScrollController( controller: controller, child: SingleChildScrollView( primary: true, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Center(child: SmartProgressButton()), ChildWidget(), Placeholder( fallbackHeight: 2000, ) ], ), ), ), ), ); } };
ChildWidget组件(独立文件)
class ChildWidget extends StatelessWidget { const ChildWidget({super.key}); @override Widget build(BuildContext context) { return Column( children: [ ElevatedButton( onPressed: () { try { final controller = PrimaryScrollController.of(context); } catch (e) { print(e); } }, child: Text('Check')) ], ); } }
解决方法
问题根源
ChildWidget中调用PrimaryScrollController.of(context)时使用的是自身的context,这个上下文并没有包含在PrimaryScrollController的子树中——PrimaryScrollController是在MyTestingPage的Scaffold内部,而ChildWidget的context是其自身组件的上下文,无法向上查找到PrimaryScrollController。
方案一:使用Builder获取正确上下文
在ChildWidget内部用Builder包裹按钮,Builder的context会继承自父级(即PrimaryScrollController所在的子树),这样就能正确获取控制器:
class ChildWidget extends StatelessWidget { const ChildWidget({super.key}); @override Widget build(BuildContext context) { return Column( children: [ Builder( builder: (context) { return ElevatedButton( onPressed: () { final controller = PrimaryScrollController.of(context); // 这里可以正常使用controller,比如controller?.animateTo(...) }, child: const Text('Check'), ); }, ) ], ); } }
方案二:直接传递ScrollController(更推荐)
跳过上下文查找,直接从MyTestingPage把ScrollController传递给ChildWidget,这种方式更直观且避免上下文相关问题:
- 修改
ChildWidget,添加接收ScrollController的参数:
class ChildWidget extends StatelessWidget { final ScrollController scrollController; const ChildWidget({super.key, required this.scrollController}); @override Widget build(BuildContext context) { return Column( children: [ ElevatedButton( onPressed: () { // 直接使用传入的控制器 scrollController.animateTo(0, duration: const Duration(milliseconds: 300), curve: Curves.easeOut); }, child: const Text('Check'), ) ], ); } }
- 在
MyTestingPage中传递控制器:
// ... children: [ Center(child: SmartProgressButton()), ChildWidget(scrollController: controller), // 这里传入controller Placeholder(fallbackHeight: 2000), ] // ...
内容的提问来源于stack exchange,提问作者Satheesh Insight

