当 ChangeNotifierProvider 中的值发生变化时如何在颤动中打开对话框

How to open a Dialog in flutter when a value changes in a ChangeNotifierProvider

我有一个屏幕使用 ChangeNotifierProvider 中的值来显示屏幕内容。正如预期的那样,当这些值发生变化时,将触发屏幕构建方法并更新屏幕内容。

如果其中一个值从 false 变为 true,我希望在该屏幕上打开一个对话框。

我想出打开此对话框的唯一方法是在值已更改并调用新构建时从构建方法启动它。

我知道 showDialog 是一种异步方法,而构建是同步的,它是一种从构建方法内部管理这些副作用的反模式。我不知道何时会调用构建方法,这可能导致每次调用构建时都会打开多个对话框。

所以,到目前为止,我只能从构建方法打开对话框,并使用内存中的布尔标志来控制对话框是否打开。像这样:

class MyScreen extends StatefulWidget {
  const MyScreen();

  @override
  State<StatefulWidget> createState() => _MyScreenState();
}

class _MyScreenState extends State<MyScreen> {
  late final myModel = Provider.of<MyModel?>(context);
   bool _isDialogShowing = false;

  @override
  void initState() {
    super.initState();
    ...
  }
  
  void _showMyDialog(BuildContext ctx) {
    showDialog(
      context: ctx,
      barrierDismissible: false,
      builder: (context) => AlertDialog(
        content: const Text("Hello I am a dialog"),
      ),
    ).then((val) {
      // The dialog has been closed
      _isDialogShowing = true;

    });
  }

  @override
  Widget build(BuildContext context) {
    // Open dialog if value from `ChangeNotifierProvider` has changed
    if (myModel?.hasToShowDialog == true && _isDialogShowing == false) {
      _isDialogShowing = true;
      Future.delayed(
        Duration.zero,
        () {
          _showMyDialog(context);
        },
      );
    }

    return Column(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Column(
          children: [
           ..... 
          ],
        ),
      ],
    );
  }
}

你知道ChangeNotifierProvider中值改变时如何正确触发对话框打开事件吗?非常感谢!!!

你可以做的是给你的 ChangeNotifier:

添加一个监听器
  late final myModel = Provider.of<MyModel?>(context);
  bool _isDialogShowing = false;

  @override
  void initState() {
    super.initState();
    myModel.addListener(_showDialog);
  }

  @override
  void dipose() {
    myModel.removeListener(_showDialog);
    super.dispose();
  }

  Future<void> _showDialog() async {
   if (_isDialogShowing || !mounted) return;
   // `hasToShowDialog` could be a getter and not a variable.
   if (myModel?.hasToShowDialog != true) return;
   _isDialogShowing = true;
   await showDialog(
     context: context,
     barrierDismissible: false,
     builder: (context) => AlertDialog(
       content: const Text("Hello I am a dialog"),
     ),
   );
   _isDialogShowing = false;
  }

我不知道你的 MyModel 长什么样,所以很难知道你还能做什么。 hasToShowDialog 可能是 getter 而不是您在问题中建议的变量。