当小部件是 MaterialApp 的直接 child 时,显示对话框不起作用

showing a dialog doesn't work when the widget is the direct child of MaterialApp


我正在尝试在 Flutter 中创建一个警告对话框,但该对话框在 MaterialApp 下不起作用,而是给出错误。下面是代码:
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Inputs and alerts'),
        ),
        body: ElevatedButton(
          child: const Text('Show Dialog'),
          onPressed: () {
            showDialog(
              context: context,
              builder: (_) {
                return AlertDialog(
                  title: Text('This is a text'),
                  content: Text('this is the content'),
                  actions: [
                    TextButton(
                      onPressed: () {
                        Navigator.of(context).pop(false);
                      },
                      child: Text('No'),
                    ),
                    TextButton(
                      onPressed: () {
                        Navigator.of(context).pop(true);
                      },
                      child: Text('Yes'),
                    )
                  ],
                );
              },
            );
          },
        ),
      ),
    );
  }
}

错误

但是当我将 ElevatedButton 提取到 stand-alone 小部件时,警报对话框工作正常。这是代码:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Inputs and alerts'),
        ),
        body: sn(),
      ),
    );
  }
}

class sn extends StatelessWidget {
  const sn({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ElevatedButton(
        child: const Text('Show Dialog'),
        onPressed: () {
          showDialog(
            context: context,
            builder: (_) {
              return AlertDialog(
                title: Text('This is a text'),
                content: Text('this is the content'),
                actions: [
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop(false);
                    },
                    child: Text('No'),
                  ),
                  TextButton(
                    onPressed: () {
                      Navigator.of(context).pop(true);
                    },
                    child: Text('Yes'),
                  )
                ],
              );
            },
          );
        },
      ),
    );
  }
}

输出

谁能告诉我这种行为的原因?非常感谢任何帮助。

发生这种情况是因为您只能调用 showDialog(context) 传递一个 BuildContext,其中 MaterialApp 作为祖先部件。您在第一个示例中的 build() 方法 中访问的上下文是 context,它没有任何 MaterialApp在上面。

就像您所做的那样,您可以通过将 Scaffold 提取到另一个小部件中以在构建方法中访问它的 BuildContext 来解决此问题。

另一种解决方案是使用 Builder 小部件。它向它的 child 公开了一个新的上下文,现在其中包含对其上方的任何小部件的引用(在本例中为 MaterialApp)。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Builder(builder: (context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Inputs and alerts'),
          ),
          body: ElevatedButton(
            child: const Text('Show Dialog'),
            onPressed: () {
              showDialog(
                context: context,
                builder: (_) {
                  return AlertDialog(
                    title: Text('This is a text'),
                    content: Text('this is the content'),
                    actions: [
                      TextButton(
                        onPressed: () {
                          Navigator.of(context).pop(false);
                        },
                        child: Text('No'),
                      ),
                      TextButton(
                        onPressed: () {
                          Navigator.of(context).pop(true);
                        },
                        child: Text('Yes'),
                      )
                    ],
                  );
                },
              );
            },
          ),
        );
      }),
    );
  }
}