Flutter问题:FloatingActionButton的Context无法找到Bloc的Provider
问题原因
你遇到的错误是因为**FloatingActionButton使用的context不在MultiBlocProvider的子树范围内**。当前代码中,MultiBlocProvider是HomePage组件build方法返回的子Widget,而你调用context.read<HomepageBloc>()时用的是HomePage自身的上下文(_HomePageState的context),这个上下文位于MultiBlocProvider的上层,所以向上查找找不到对应的Bloc实例。
解决方案
有两种简单可行的修复方式:
方式一:将MultiBlocProvider移到HomePage的父级
把Bloc的提供逻辑放在HomePage的上层(比如路由配置或MaterialApp中),这样HomePage的上下文就能直接找到Bloc:
路由配置示例(修改MaterialApp部分)
MaterialApp( home: MultiBlocProvider( providers: [ BlocProvider(create: (context) => HomepageBloc()..add(LoadHomepage())), ], child: const HomePage(), ), );
修改HomePage的build方法
移除内部的MultiBlocProvider,直接返回Scaffold:
@override Widget build(BuildContext context) { return Scaffold( appBar: const UpperNavBar().build(context), endDrawer: const CustomDrawer(), body: Center( child: BlocBuilder<HomepageBloc, HomepageState>( builder: (context, state) { if (state is HomepageInitial) { return CircularProgressIndicator( color: Theme.of(context).colorScheme.primary); } if (state is HomepageNoEmergency) { return Column( children: <Widget>[ const WeatherForecast(), CustomTextButton( height: 70, text: "Safe Places", icon: Icon( Icons.map_outlined, color: Theme.of(context).colorScheme.secondary, ), textStyle: Theme.of(context).textTheme.titleLarge, ) ], ); } if (state is HomepageEmergency) { return Column( children: <Widget>[ const WeatherForecast(), CustomTextButton( height: 70, text: "Safe Places", icon: Icon( Icons.map_outlined, color: Theme.of(context).colorScheme.secondary, ), textStyle: Theme.of(context).textTheme.titleLarge, ), CustomTextButton( height: 100, text: "HELP!", textStyle: Theme.of(context).textTheme.titleLarge) ], ); } else { return const Center( child: Text("Something went wrong"), ); } }, ), ), floatingActionButton: FloatingActionButton( onPressed: () { context.read<HomepageBloc>().add(EmergencyHappened()); }, ), ); }
方式二:用Builder包裹Scaffold,使用子树上下文
如果不想修改父级代码,可以在MultiBlocProvider的child中添加Builder,让Scaffold及其子Widget使用Builder提供的子树上下文,这个上下文能找到Bloc:
@override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider(create: (BuildContext context) => HomepageBloc()..add(LoadHomepage())), ], child: Builder( builder: (innerContext) { // 子树上下文 return Scaffold( appBar: const UpperNavBar().build(innerContext), endDrawer: const CustomDrawer(), body: Center( child: BlocBuilder<HomepageBloc, HomepageState>( builder: (context, state) { if (state is HomepageInitial) { return CircularProgressIndicator( color: Theme.of(innerContext).colorScheme.primary); } if (state is HomepageNoEmergency) { return Column( children: <Widget>[ const WeatherForecast(), CustomTextButton( height: 70, text: "Safe Places", icon: Icon( Icons.map_outlined, color: Theme.of(innerContext).colorScheme.secondary, ), textStyle: Theme.of(innerContext).textTheme.titleLarge, ) ], ); } if (state is HomepageEmergency) { return Column( children: <Widget>[ const WeatherForecast(), CustomTextButton( height: 70, text: "Safe Places", icon: Icon( Icons.map_outlined, color: Theme.of(innerContext).colorScheme.secondary, ), textStyle: Theme.of(innerContext).textTheme.titleLarge, ), CustomTextButton( height: 100, text: "HELP!", textStyle: Theme.of(innerContext).textTheme.titleLarge) ], ); } else { return const Center( child: Text("Something went wrong"), ); } }, ), ), floatingActionButton: FloatingActionButton( onPressed: () { innerContext.read<HomepageBloc>().add(EmergencyHappened()); // 使用子树上下文 }, ), ); }, ), ); }
说明
两种方式都能解决问题:方式一更符合Bloc的常见使用习惯(在页面入口处提供Bloc),方式二则适合快速调整当前页面的代码。修复后点击FloatingActionButton就能正常触发EmergencyHappened事件,切换到显示HELP按钮的状态。
内容的提问来源于stack exchange,提问作者InvalidHop
相关产品推荐
相关产品推荐

