Flutter中showDialog报错:MaterialLocalizations缺失问题求助
Flutter showDialog 报错:缺少MaterialLocalizations祖先组件的解决方案
我明天要提交下面的Flutter代码,但第38行的showDialog调用一直报错,提示MyApp组件缺少MaterialLocalizations祖先组件。已经折腾了3小时(谷歌搜索、咨询ChatGPT)还是没解决,附上完整代码和报错信息,求排查原因并给解决方案。
完整代码
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Expanded( flex: 5, child: Container( color: Color(0xFFf4dfc1), ), ), Expanded( flex: 1, child: Container( color: Colors.white, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Container( width: 50.0, height: 50.0, decoration: BoxDecoration( color: Color(0xFFb5e5e5), borderRadius: BorderRadius.circular(5.0), ), child: IconButton( onPressed: () { print(452345256); showDialog( context: context, builder: (context) => AlertDialog( title: Text('My Dialog Title'), content: Text('My Dialog Content'), ), ); }, icon: Icon( Icons.access_time_rounded, size: 30.0, color: Colors.white, ), constraints: BoxConstraints( minWidth: 50.0, minHeight: 50.0, ), ), ), Container( width: 50.0, height: 50.0, decoration: BoxDecoration( color: Color(0xFFc0e1b1), borderRadius: BorderRadius.circular(5.0), ), child: IconButton( onPressed: () { print(1); }, icon: Icon( Icons.play_arrow_rounded, size: 30.0, color: Colors.white, ), constraints: BoxConstraints( minWidth: 50.0, minHeight: 50.0, ), ), ), Container( width: 50.0, height: 50.0, decoration: BoxDecoration( color: Color(0xFFf0c8c9), borderRadius: BorderRadius.circular(5.0), ), child: IconButton( onPressed: () { print(1); }, icon: Icon( Icons.restart_alt_rounded, size: 30.0, color: Colors.white, ), constraints: BoxConstraints( minWidth: 50.0, minHeight: 50.0, ), ), ), ], ), ), ), Expanded( flex: 5, child: Container( color: Color(0xFFb6876b), ), ), ], ), ), ); } }
报错信息
MyApp widgets require MaterialLocalizations to be provided by a Localizations widget ancestor. The material library uses Localizations to generate messages, labels, and abbreviations. To introduce a MaterialLocalizations, either use a MaterialApp at the root of your application to include them automatically, or add a Localization widget with a MaterialLocalizations delegate. The specific widget that could not find a MaterialLocalizations ancestor was: MyApp The ancestors of this widget were: [root])
问题原因
核心是用错了BuildContext:你在showDialog里传入的context是MyApp组件build方法的上下文,这个上下文位于MaterialApp的上层——而MaterialApp才是负责提供MaterialLocalizations的组件。也就是说,这个context的组件树里根本没有MaterialLocalizations的祖先,调用依赖它的showDialog自然会报错。
解决方案
方案1:把页面内容抽成单独组件
把MaterialApp的home内容抽成一个新的StatelessWidget,新组件的context属于MaterialApp的子树,能正常访问MaterialLocalizations。
修改后的代码:
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), // 替换为新组件 ); } } // 新增页面组件 class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Expanded( flex: 5, child: Container( color: Color(0xFFf4dfc1), ), ), Expanded( flex: 1, child: Container( color: Colors.white, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Container( width: 50.0, height: 50.0, decoration: BoxDecoration( color: Color(0xFFb5e5e5), borderRadius: BorderRadius.circular(5.0), ), child: IconButton( onPressed: () { print(452345256); showDialog( context: context, // 这里用HomePage的context,属于MaterialApp子树 builder: (context) => AlertDialog( title: Text('My Dialog Title'), content: Text('My Dialog Content'), ), ); }, icon: Icon( Icons.access_time_rounded, size: 30.0, color: Colors.white, ), constraints: BoxConstraints( minWidth: 50.0, minHeight: 50.0, ), ), ), // 其他两个IconButton代码不变 Container( width: 50.0, height: 50.0, decoration: BoxDecoration( color: Color(0xFFc0e1b1), borderRadius: BorderRadius.circular(5.0), ), child: IconButton( onPressed: () { print(1); }, icon: Icon( Icons.play_arrow_rounded, size: 30.0, color: Colors.white, ), constraints: BoxConstraints( minWidth: 50.0, minHeight: 50.0, ), ), ), Container( width: 50.0, height: 50.0, decoration: BoxDecoration( color: Color(0xFFf0c8c9), borderRadius: BorderRadius.circular(5.0), ), child: IconButton( onPressed: () { print(1); }, icon: Icon( Icons.restart_alt_rounded, size: 30.0, color: Colors.white, ), constraints: BoxConstraints( minWidth: 50.0, minHeight: 50.0, ), ), ), ], ), ), ), Expanded( flex: 5, child: Container( color: Color(0xFFb6876b), ), ), ], ), ); } }
方案2:用Builder组件包裹Scaffold
如果不想抽组件,用Builder包裹Scaffold,它会提供一个属于MaterialApp子树的context,直接用这个context调用showDialog即可。
修改后的关键代码:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Builder( // 新增Builder组件 builder: (context) { // 这里的context属于MaterialApp子树 return Scaffold( body: Column( // ... 其他代码不变 children: [ Expanded( flex:1, child: Container( child: Row( children: [ Container( child: IconButton( onPressed: () { showDialog( context: context, // 使用Builder提供的context builder: (context) => AlertDialog( title: Text('My Dialog Title'), content: Text('My Dialog Content'), ), ); }, // ... 其他代码不变 ), ), // ... 其他按钮代码不变 ], ), ), ), // ... 其他代码不变 ], ), ); }, ), ); } }
内容的提问来源于stack exchange,提问作者user21550829
相关产品推荐
相关产品推荐

