没有找到MaterialLocalizations - MyApp小部件需要Localizations小部件的祖先提供MaterialLocalizations。

44

我只是想创建一个带有按钮的应用程序,当按下按钮时,它会显示警报消息。

但是出现了以下错误:

我参考了这个视频编写了这段代码。

我正在使用adb连接在真机上运行该应用程序。

请帮帮我..!

代码:

import 'package:flutter/material.dart';

void main(){
  runApp(MyApp());
}

class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Test",
      home: Scaffold(
        appBar: AppBar(title: Text("Test")),
        body: Container(
          child: Center(
            child: RaisedButton(
              color: Colors.redAccent,
              textColor: Colors.white,
              onPressed: (){testAlert(context);},
              child: Text("PressMe"),
            ),
          ),
        ),
      ),
    );
  }
  void testAlert(BuildContext context){
    var alert = AlertDialog(
      title: Text("Test"),
      content: Text("Done..!"),
    );

    showDialog(
        context: context,
        builder: (BuildContext context){
          return alert;
        }
    );
  }
}

这是我编写的代码。我也尝试将testAlert()函数的内容直接插入到onPressed中,但不起作用。

错误

Performing hot reload...
Syncing files to device ZUK Z2131...
Reloaded 0 of 419 libraries in 1,929ms.
I/flutter (18652): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter (18652): The following assertion was thrown while handling a gesture:
I/flutter (18652): No MaterialLocalizations found.
I/flutter (18652): MyApp widgets require MaterialLocalizations to be provided by a Localizations widget ancestor.
I/flutter (18652): Localizations are used to generate many different messages, labels,and abbreviations which are used
I/flutter (18652): by the material library. 
I/flutter (18652): To introduce a MaterialLocalizations, either use a  MaterialApp at the root of your application to
I/flutter (18652): include them automatically, or add a Localization widget with a MaterialLocalizations delegate.
I/flutter (18652): The specific widget that could not find a MaterialLocalizations ancestor was:
I/flutter (18652):   MyApp
I/flutter (18652): The ancestors of this widget were:
I/flutter (18652):   [root]
I/flutter (18652): 
I/flutter (18652): When the exception was thrown, this was the stack:
I/flutter (18652): #0      debugCheckHasMaterialLocalizations.<anonymous closure> (package:flutter/src/material/debug.dart:124:7)
I/flutter (18652): #1      debugCheckHasMaterialLocalizations (package:flutter/src/material/debug.dart:127:4)
I/flutter (18652): #2      showDialog (package:flutter/src/material/dialog.dart:635:10)
I/flutter (18652): #3      MyApp.testAlert (package:flutter_app/main.dart:33:5)
I/flutter (18652): #4      MyApp.build.<anonymous closure> (package:flutter_app/main.dart:19:29)
I/flutter (18652): #5      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
I/flutter (18652): #6      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
I/flutter (18652): #7      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
I/flutter (18652): #8      TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
I/flutter (18652): #9      TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
I/flutter (18652): #10     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
I/flutter (18652): #11     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
I/flutter (18652): #12     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
I/flutter (18652): #13     _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:180:19)
I/flutter (18652): #14     _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:158:22)
I/flutter (18652): #15     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:138:7)
I/flutter (18652): #16     _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
I/flutter (18652): #17     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
I/flutter (18652): #18     _invoke1 (dart:ui/hooks.dart:168:13)
I/flutter (18652): #19     _dispatchPointerDataPacket (dart:ui/hooks.dart:122:5)
I/flutter (18652): 
I/flutter (18652): Handler: onTap
I/flutter (18652): Recognizer:
I/flutter (18652):   TapGestureRecognizer#d5d82(debugOwner: GestureDetector, state: possible, won arena, finalPosition:
I/flutter (18652):   Offset(220.2, 406.1), sent tap down)
I/flutter (18652): ════════════════════════════════════════════════════════════════════════════════════════════════════
W/ActivityThread(18652): handleWindowVisibility: no activity for token android.os.BinderProxy@59b4e8d
I/ViewRootImpl(18652): CPU Rendering VSync enable = true
13个回答

48
这是因为您传递给showDialog方法的上下文是一个没有MaterialLocalizations小部件的上下文,MaterialLocalizations小部件会隐式地通过MaterialApp小部件添加。要解决此问题,请尝试以下操作:
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Test",
      home: TestPage(),
    );
  }
}

class TestPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Test")),
      body: Container(
        child: Center(
          child: RaisedButton(
            color: Colors.redAccent,
            textColor: Colors.white,
            onPressed: () {
              testAlert(context);
            },
            child: Text("PressMe"),
          ),
        ),
      ),
    );
  }

  void testAlert(BuildContext context) {
    var alert = AlertDialog(
      title: Text("Test"),
      content: Text("Done..!"),
    );

    showDialog(
        context: context,
        builder: (BuildContext context) {
          return alert;
        });
  }
}

25
如果您能提供一些关于您的代码具体执行操作的解释,那就太好了。 - K.Amanov
2
我看到的是Jordan正在将有问题的Widget移动到它自己的无状态Widget类中,以便不使用MaterialApp()所使用的相同上下文。 - Sam Ramezanli

45

在我的情况下,一个简单的解决方法是将MaterialApp小部件移至main()方法中。

main() {
  runApp(MaterialApp(home: App()));
}

对于好奇的人来说,这个答案和被接受的答案是一样的。被接受的答案使用了 MaterialApp 构造函数的 2 个参数,而这个答案使用了 MaterialApp 构造函数的 1 个参数。 - Johan

28
这也会发生在你切换到不被 GlobalMaterialLocalizations 委托支持的语言时。这是一条需要仔细理解的信息,因为它说您应该将 MaterialApp 放置在树顶,但可能已经存在。

在我的情况下,我要本地化的语言(英国威尔士语 - cy-GB)没有自动提供支持。我必须编写自己的委托以获取样板字符串,并将其添加到应用程序根目录下的本地化列表中。

白俄罗斯代表代码在 此处。我对其进行了修改,以支持威尔士语。它包含日期格式信息以及大约70个 Material Design 认为您可能需要的常用短语,例如“SELECT ALL”、“Page <x> of <y>”等。

如果您需要创建一个覆盖全局材料本地化未列出的语言的委托,则一旦创建完成,查找您的代码库,在树的顶部附近,您将有一行类似于

MaterialApp(
 localizationsDelegates: [
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
   GlobalCupertinoLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', ''), // English, no country code
    const Locale('he', ''), // Hebrew, no country code
    const Locale.fromSubtags(languageCode: 'zh')
  ],
  // ...
)

只需将CyMaterialLocalizations.delegate(或您称为新语言代表的任何内容)添加到localizationsDelegates列表中。


@Chris -- 它在抱怨你在委托中使用的DateFormat。我不得不在我的威尔士语委托中重用en-GB日期格式。这本身会导致另一个崩溃(我已经提出了一个问题来解决它)。也有一种方法可以解决这个问题。我稍后会在我的答案中添加详细信息。这是棘手的东西。 - Rob Lyndon
我通过在应用程序顶部的FutureBuilder中调用await GlobalMaterialLocalizations.delegate.load(supportedLocales[0])来实现这一点,其中supportedLocales是我设置的不可变数组。虽然这不是理想的解决方案,但它可以工作,并且没有明显的延迟。 - Rob Lyndon
2
那么,这些“神奇字符串”(如“en”,“fr”)的列表在哪里呢?也许我打错了一个字母。例如,我需要为马达加斯加找到对应的字符串。只是为了确保在创建样板代码之前,该字符串不存在。 - Akbar Pulatov
你如何知道哪个区域设置导致了这个错误?@RobLyndon - Edblocker
我能理解这个问题,但实际上只有少数用户遇到了这个问题,而我无法重现它。你能帮忙吗? - Apoorv Pandey
显示剩余5条评论

6

MaterialApp中添加localizationsDelegatessupportedLocales解决了我的问题。

localizationsDelegates: [
      GlobalMaterialLocalizations.delegate,
      GlobalWidgetsLocalizations.delegate,
      GlobalCupertinoLocalizations.delegate,
    ],

supportedLocales: [
      Locale('en', 'US'),
    ],

1
这是我亲测有效的方法,也是我们可以在官方文档 https://docs.flutter.dev/development/accessibility-and-localization/internationalization#setting-up 中找到的。 - Moussa

4

我在RaisedButton内使用showTimePicker时遇到了相同的问题,

我进行了重构:

runApp 
  |__MaterialApp
    |__ StatefulWidget/StatelessWidget
      |__SafeArea
        |__Scaffold
          |__ RaisedButton
            |__ showTimePicker

这是样本解决方案:

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', 'US'), 
      ],
      home: Sample(),
    ),
  );
}

class Sample extends StatefulWidget {
  @override
  _SampleState createState() => _SampleState();
}

class _SampleState extends State<Sample> {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Center(
          child: RaisedButton(
            child: Text('Time Picker'),
            onPressed: () {
              showTimePicker(
                context: context,
                initialTime: TimeOfDay(hour: 10, minute: 47),
                builder: (BuildContext context, Widget child) {
                  return MediaQuery(
                    data: MediaQuery.of(context)
                        .copyWith(alwaysUse24HourFormat: true),
                    child: child,
                  );
                },
              );
            },
          ),
        ),
      ),
    );
  }
}

1

我遇到了同样的问题,需要在界面中显示对话框。

initState();

我是这样解决的,

Future.delayed(Duration.zero, () {
  showGameOverDailog(context);
});

1

另一种方法是使用Builder包装调用showDialog的最内层小部件。在这种情况下,最内层小部件是TextButton(请注意,我用TextButton替换了已弃用的RaisedButton)。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Test")),
        body: Container(
          child: Builder(
            builder: (context) {
              return TextButton(
                child: const Text('Show'),
                onPressed: () {
                  showDialog(
                    context: context,
                    builder: (_) => AlertDialog(
                      title: Text("Test"),
                      content: Text("Done..!"),
                    ),
                  );
                },
              );
            },
          ),
        ),
      ),
    );
  }
}

1
Jeff Atwood 不喜欢这种编码风格:https://blog.codinghorror.com/flattening-arrow-code/ - Second Person Shooter

0
在我的情况下,当我尝试将这条记录插入StatefulWidget时出现了这个问题。
const MyApp({Key? key}) : super(key: key);

这并没有真正回答问题。如果你有不同的问题,可以通过点击[提问](https://stackoverflow.com/questions/ask)来询问。如果您希望在此问题获得新的答案时收到通知,您可以[关注此问题](https://meta.stackexchange.com/q/345661)。一旦您获得足够的[声望](https://stackoverflow.com/help/whats-reputation),您还可以[添加悬赏](https://stackoverflow.com/help/privileges/set-bounties)以吸引更多人关注此问题。- [来自审查](/review/late-answers/31580710) - srikanth7785

0
localizationsDelegates: [
    MonthYearPickerLocalizations.delegate,
  ],

我正在使用一个 MonthYearPicker 包,我必须将其添加到我的 MaterialApp Widget 中。

0
我遇到了这个问题两天,然后在两天后找到了一个小技巧解决了它。
我只保留了supportedLocales: const [Locale('en', 'IN')]并删除了其他的。
另一种方法是删除supportedLocales: const [Locale('en', 'IN')]也对我起到了作用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接