从父级更新警报模态子级

Update alert modal child from parent

我在按下按钮时调用显示我的对话框以显示父项中的上传进度。

在整个上传功能的部分中,我正在更新状态,例如 setState(() => _progress = _progress + 0.05);。但是,我的对话框值也没有正确更新。我认为对话没有重建。如何让对话框监听此值并在更新时重建?

对话代码:

Future<void> _showMyDialog() async {
return showDialog<void>(
  context: context,
  barrierDismissible: true, // user must tap button!
  builder: (BuildContext context) {
    return AlertDialog(
        insetPadding: EdgeInsets.all(10.0),
        content: StatefulBuilder(
            builder: (BuildContext context, StateSetter setState) {
          return Container(
            height: MediaQuery.of(context).size.width * 0.3,
            width: MediaQuery.of(context).size.width * 0.9,
            child: Center(
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                  Text(
                    "Uploading...",
                    style: TextStyle(
                        fontWeight: FontWeight.bold, fontSize: 20),
                  ),
                  SizedBox(height: 30),
                  ClipRRect(
                      borderRadius: BorderRadius.all(Radius.circular(10)),
                      child: LinearProgressIndicator(
                        minHeight: 15,
                        value: _progress,
                      ))
                ])),
          );
        }));
  },
);

触发对话框代码:

onPressed: () async {
              setState(() => loading = true);
                _showMyDialog();
                await uploadAudio();           
                setState(() => loading = false);
           },

您可以复制粘贴 运行 下面的完整代码
您可以使用 ValueNotifier<double>ValueListenableBuilder
代码片段

  final ValueNotifier<double> _progress = ValueNotifier<double>(0);

  Future<void> uploadAudio() async {
    await Future.delayed(Duration(seconds: 2), () {});
    _progress.value = 0.1;
    ...
    await Future.delayed(Duration(seconds: 2), () {});
    _progress.value = 1.0;
  }

  Future<void> _showMyDialog() async {
    ...
                      ClipRRect(
                          borderRadius: BorderRadius.all(Radius.circular(10)),
                          child: ValueListenableBuilder(
                              builder: (BuildContext context, double value,
                                  Widget child) {
                                return LinearProgressIndicator(
                                    minHeight: 15, value: value);
                              },
                              valueListenable: _progress))
                    ])),
              );
            }));
      },
    );
  }

  ElevatedButton(
                onPressed: () async {
                  setState(() => loading = true);
                  _progress.value = 0;
                  _showMyDialog();
                  await uploadAudio();
                  setState(() => loading = false);
                },
                child: Text('Upload')),

工作演示

完整代码

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool loading;
  final ValueNotifier<double> _progress = ValueNotifier<double>(0);

  Future<void> uploadAudio() async {
    await Future.delayed(Duration(seconds: 2), () {});
    _progress.value = 0.1;
    await Future.delayed(Duration(seconds: 2), () {});
    _progress.value = 0.5;
    await Future.delayed(Duration(seconds: 2), () {});
    _progress.value = 0.7;
    await Future.delayed(Duration(seconds: 2), () {});
    _progress.value = 1.0;
  }

  Future<void> _showMyDialog() async {
    return showDialog<void>(
      context: context,
      barrierDismissible: true, // user must tap button!
      builder: (BuildContext context) {
        return AlertDialog(
            insetPadding: EdgeInsets.all(10.0),
            content: StatefulBuilder(
                builder: (BuildContext context, StateSetter setState) {
              return Container(
                height: MediaQuery.of(context).size.width * 0.3,
                width: MediaQuery.of(context).size.width * 0.9,
                child: Center(
                    child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                      Text(
                        "Uploading...",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 20),
                      ),
                      SizedBox(height: 30),
                      ClipRRect(
                          borderRadius: BorderRadius.all(Radius.circular(10)),
                          child: ValueListenableBuilder(
                              builder: (BuildContext context, double value,
                                  Widget child) {
                                return LinearProgressIndicator(
                                    minHeight: 15, value: value);
                              },
                              valueListenable: _progress))
                    ])),
              );
            }));
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ElevatedButton(
                onPressed: () async {
                  setState(() => loading = true);
                  _progress.value = 0;
                  _showMyDialog();
                  await uploadAudio();
                  setState(() => loading = false);
                },
                child: Text('Upload')),
          ],
        ),
      ),
    );
  }
}