You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从独立类调用Flutter对话框?封装可复用对话框组件

Extracting the Sub-Dialog into a Reusable Widget

Got it, let's fix this by turning that nested sub-dialog into a standalone, reusable widget that you can trigger from any button. Here's a clean approach:

Step 1: Create the Reusable Sub-Dialog Widget

First, we'll wrap the sub-dialog in its own StatefulWidget (we use stateful here in case you need to manage internal state later, like file previews or form inputs). We'll also add a static show method to make calling it super easy:

class SecondSubdialog extends StatefulWidget {
  // Optional callback for when the user taps "Yes"
  final VoidCallback? onConfirm;

  const SecondSubdialog({Key? key, this.onConfirm}) : super(key: key);

  // Static method to show the dialog directly
  static void show(BuildContext context, {VoidCallback? onConfirm}) {
    showDialog(
      context: context,
      builder: (ctx) => SecondSubdialog(onConfirm: onConfirm),
    );
  }

  @override
  State<SecondSubdialog> createState() => _SecondSubdialogState();
}

class _SecondSubdialogState extends State<SecondSubdialog> {
  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Text(
        "Second subdialog title",
        textAlign: TextAlign.center,
      ),
      content: Container(
        width: 150,
        height: 200,
        decoration: BoxDecoration(
          border: Border.all(width: 1, color: Colors.grey),
        ),
        child: const Text('Here will be file'),
        alignment: Alignment.center,
      ),
      actions: <Widget>[
        FlatButton(
          onPressed: () => Navigator.of(context).pop(),
          child: const Text("No"),
        ),
        FlatButton(
          onPressed: () {
            Navigator.of(context).pop();
            // Trigger the confirm callback if provided
            widget.onConfirm?.call();
          },
          child: const Text("Yes"),
        ),
      ],
    );
  }
}

Step 2: Update Your Original Code to Use the Reusable Widget

Now you can replace the nested dialog code with calls to our new widget. Here's the updated _MapState class:

class _MapState extends State<_Map> {
  final _titleController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('App name'),
        actions: <Widget>[
          IconButton(
            icon: const Icon(Icons.add),
            onPressed: () {
              showDialog(
                context: context,
                builder: (ctx) => AlertDialog(
                  title: const Text(
                    "Dialog title",
                    textAlign: TextAlign.center,
                  ),
                  content: TextField(
                    decoration: const InputDecoration(labelText: 'Title'),
                    controller: _titleController,
                  ),
                  actions: <Widget>[
                    FlatButton(
                      onPressed: () => Navigator.of(ctx).pop(),
                      child: const Text("No"),
                    ),
                    FlatButton(
                      onPressed: () {
                        Navigator.of(ctx).pop(); // Close the first dialog first (optional)
                        // Call our reusable sub-dialog
                        SecondSubdialog.show(context, onConfirm: () {
                          // Add your state logic here
                          print('Handling state after sub-dialog confirm!');
                        });
                      },
                      child: const Text("Yes"),
                    ),
                  ],
                ),
              );
            },
          ),
        ],
      ),
      body: const Text('App body here'),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          FloatingActionButton(
            onPressed: () {
              // Call the same sub-dialog from the floating button
              SecondSubdialog.show(context, onConfirm: () {
                print('Floating button dialog confirmed!');
              });
            },
            child: const Icon(Icons.add, color: Colors.white),
            backgroundColor: Colors.green,
            heroTag: 'mapZoomIn',
          ),
        ],
      ),
    );
  }
}

Key Benefits of This Approach

  • Cleaner Code: Your main widget doesn't get cluttered with nested dialog logic
  • Reusability: Call SecondSubdialog.show(context) from any button or event in your app
  • Flexibility: The optional onConfirm callback lets you handle post-confirmation logic differently depending on where you call the dialog
  • Maintainability: If you need to update the sub-dialog's UI or logic later, you only have to change it in one place

内容的提问来源于stack exchange,提问作者Andreas Hunter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:49:24