Flutter自定义AppBar调用Scaffold.of()无法获取上下文报错求助
错误原因
你调用Scaffold.of()时传入的context来自MyApp的build方法,此时这个context对应的组件树节点,还没有将你创建的Scaffold作为祖先节点——因为这个Scaffold本身就是MyApp.build方法返回的子组件,从这个context往上遍历自然找不到Scaffold实例。
解决方案1:拆分主页组件(官方推荐)
把Scaffold所在的页面抽成单独的StatelessWidget,新组件的build方法拿到的context就会包含上层的Scaffold了。
修改main.dart代码:
void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Food App', theme: ThemeData( primaryColor: kPrimaryColor, scaffoldBackgroundColor: Colors.white, ), // 把Scaffold移到单独的HomePage组件里 home: HomePage() ); } } // 新增单独的主页组件 class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( bottomNavigationBar: BottomNavBar(), body: HomeScreen(), drawer: CustomDrawer(), // 这里传入的context是HomePage的,父级已经有Scaffold了 appBar: homeAppBar(context), ); } }
你后续写的无回调版本的homeAppBar代码不需要修改,可直接使用。
解决方案2:用Builder包裹AppBar(无需修改现有组件逻辑)
你之前尝试用Builder报错是因为放置位置不对,不需要在homeAppBar内部包裹,只要在给Scaffold的appBar参数赋值时外层套Builder即可,Builder会生成一个位于Scaffold子层级的新context:
void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Food App', theme: ThemeData( primaryColor: kPrimaryColor, scaffoldBackgroundColor: Colors.white, ), home: Scaffold( bottomNavigationBar: BottomNavBar(), body: HomeScreen(), drawer: CustomDrawer(), // 外层加Builder,传入子层级的新context appBar: Builder( builder: (childContext) => homeAppBar(childContext), ), )); } }
该方案下你写的无回调版本homeAppBar也可以直接使用。
解决方案3:给Scaffold绑定GlobalKey
如果不想调整组件结构,也可以直接给Scaffold指定全局key,通过key直接调用openDrawer方法,不需要依赖context查找:
修改main.dart代码:
void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // 定义Scaffold的全局Key final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Food App', theme: ThemeData( primaryColor: kPrimaryColor, scaffoldBackgroundColor: Colors.white, ), home: Scaffold( // 给Scaffold绑定key key: _scaffoldKey, bottomNavigationBar: BottomNavBar(), body: HomeScreen(), drawer: CustomDrawer(), appBar: homeAppBar(_scaffoldKey, context), )); } }
对应修改homeAppBar的入参:
AppBar homeAppBar(GlobalKey<ScaffoldState> scaffoldKey, BuildContext context) { return AppBar( backgroundColor: Colors.white, elevation: 0, leading: IconButton( icon: SvgPicture.asset("assets/icons/menu.svg"), // 直接通过key调用打开抽屉方法 onPressed: () => scaffoldKey.currentState?.openDrawer(), ), // 其余代码保持不变 title: RichText( text: TextSpan( style: Theme.of(context) .textTheme .headline6 ?.copyWith(fontWeight: FontWeight.bold), children: [ TextSpan( text: "Makana", style: TextStyle(color: ksecondaryColor), ), TextSpan( text: "Food", style: TextStyle(color: kPrimaryColor), ), ], ), ), actions: <Widget>[ IconButton( icon: SvgPicture.asset("assets/icons/notification.svg"), onPressed: () {}, ), ], ); }
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

