You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter子树中获取PrimaryScrollController报错问题求助

问题:PrimaryScrollController.of()获取控制器失败报错

在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,这种方式更直观且避免上下文相关问题:

  1. 修改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'),
        )
      ],
    );
  }
}
  1. 在MyTestingPage中传递控制器:
// ...
children: [
  Center(child: SmartProgressButton()),
  ChildWidget(scrollController: controller), // 这里传入controller
  Placeholder(fallbackHeight: 2000),
]
// ...

内容的提问来源于stack exchange,提问作者Satheesh Insight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:30:17