Flutter AlertDialog的颤振生成器未由父级中的SetState更新

Flutter AlertDialog的颤振生成器未由父级中的SetState更新,flutter,dart,builder,flutter-alertdialog,Flutter,Dart,Builder,Flutter Alertdialog,我有一个父StatefulWidget和一个无状态Widget子部件,它返回一个AlertDialog对话框。当按下“绿色下载”按钮时,无状态小部件是从StatefulWidget中的生成器生成的。(在AlertDialog中确认后,完整代码将获取并存储数据) AlertDialog对话框中有一个DropDownButtonForm字段。我内置了自己的验证和错误消息,以确保关联的值不为null。(我无法获得DropdownButtonFormField的内置验证来显示整个错误消息,除非它被切断)

我有一个父StatefulWidget和一个无状态Widget子部件,它返回一个AlertDialog对话框。当按下“绿色下载”按钮时,无状态小部件是从StatefulWidget中的生成器生成的。(在AlertDialog中确认后,完整代码将获取并存储数据)

AlertDialog对话框中有一个DropDownButtonForm字段。我内置了自己的验证和错误消息,以确保关联的值不为null。(我无法获得DropdownButtonFormField的内置验证来显示整个错误消息,除非它被切断)

我不明白为什么我的AlertDialog没有被更新以显示回调SetState之后的错误消息,即使使用StatefulBuilder(我可能没有正确使用)。我尝试过使用StatefulWidget

电流输出: 当您按下AlertDialog中的yes按钮,但下拉值为null或空时,AlertDialog不会更新以在AlertDialog中显示错误消息的中心小部件。如果弹出AlertDialog并重新打开,它将显示错误消息

所需输出 当您按下AlertDialog中的yes按钮,但下拉值为null或空时,AlertDialog将更新,以在AlertDialog中显示显示错误消息的中心小部件

请问你能帮忙吗

可用于重新创建以下内容的代码:

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:io';

void main() {
  runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isLoading = false;
  bool _downloaded = false;

  File cardImage;

  String _languageDropdownValue;

  bool isError = false;

  List<Map<String, String>> _languages = [
    {'code': 'en', 'value': 'English'},
    {'code': 'fr', 'value': 'French'},
  ];

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: _downloaded
            ? IconButton(
                alignment: Alignment.center,
                padding: EdgeInsets.symmetric(horizontal: 0),
                icon: Icon(
                  Icons.open_in_new,
                  size: 45.0,
                  color: Colors.green,
                ),
                onPressed: () {
                  print('Open button pressed');
                })
            : _isLoading
                ? CircularProgressIndicator(
                    valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
                  )
                : IconButton(
                    alignment: Alignment.center,
                    padding: EdgeInsets.symmetric(horizontal: 0),
                    icon: Icon(
                      Icons.download_rounded,
                      size: 45.0,
                      color: Colors.green,
                    ),
                    onPressed: () {
                      print('Download button pressed');
                      showDialog(
                        context: context,
                        builder: (context) {
                          return StatefulBuilder(
                              builder: (context, StateSetter setState) {
                            return DownloadScreen(
                              callbackFunction: alertDialogCallback,
                              dropDownFunction: alertDialogDropdown,
                              isError: isError,
                              languages: _languages,
                              languageDropdownValue: _languageDropdownValue,
                            );
                          });
                        },
                      );
                    }),
      ),
    );
  }

  String alertDialogDropdown(String newValue) {
    setState(() {
      _languageDropdownValue = newValue;
    });
    return newValue;
  }

  alertDialogCallback() {
    if (_languageDropdownValue == null || _languageDropdownValue.isEmpty) {
      setState(() {
        isError = true;
      });
    } else {
      setState(() {
        isError = false;
        startDownload();
      });
    }
  }

  void startDownload() async {
    print('selected language is: $_languageDropdownValue');
    Navigator.pop(context);
    print('start download');
    setState(() => _downloaded = true);
  }
}

class DownloadScreen extends StatelessWidget {
  DownloadScreen(
      {@required this.callbackFunction,
      @required this.dropDownFunction,
      @required this.isError,
      @required this.languages,
      @required this.languageDropdownValue});

  final Function callbackFunction;
  final Function dropDownFunction;
  final String languageDropdownValue;
  final bool isError;
  final List<Map<String, String>> languages;

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      contentPadding: EdgeInsets.fromLTRB(24, 24, 24, 14),
      title: Text('Confirm purchase'),
      content: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('Please select the guide language:'),
          Flexible(
            child: DropdownButtonFormField(
              isExpanded: false,
              isDense: true,
              dropdownColor: Colors.white,
              value: languageDropdownValue,
              hint: Text(
                'Preferred Language',
                style: TextStyle(color: Colors.grey),
              ),
              items: languages.map((map) {
                return DropdownMenuItem(
                  value: map['code'],
                  child: Text(
                    map['value'],
                    overflow: TextOverflow.ellipsis,
                  ),
                );
              }).toList(),
              onChanged: (String newValue) => dropDownFunction(newValue),
              decoration: InputDecoration(
                filled: true,
                fillColor: Colors.white,
                labelStyle: TextStyle(color: Colors.grey),
                hintStyle: TextStyle(color: Colors.grey),
                errorStyle: TextStyle(fontSize: 17.0),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(10),
                  ),
                  borderSide: BorderSide.none,
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: BorderSide(color: Colors.blue, width: 2),
                  borderRadius: BorderRadius.all(
                    Radius.circular(10),
                  ),
                ),
              ),
            ),
          ),
          isError
              ? Center(
                  child: Padding(
                    padding: const EdgeInsets.only(bottom: 8.0),
                    child: Text(
                      'Please select a language',
                      style: TextStyle(
                        color: Colors.red,
                      ),
                    ),
                  ),
                )
              : Container(),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 20.0),
            child: Text('Are you sure you want to purchase this audio guide?'),
          ),
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.max,
            children: [
              ElevatedButton(
                onPressed: callbackFunction,
                child: Text('Yes'),
              ),
              SizedBox(
                width: 40,
              ),
              ElevatedButton(
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
                child: Text('No'),
                style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.blue),
                ),
              ),
            ],
          )
        ],
      ),
    );
  }
}
导入“包装:颤振/材料.省道”;
进口“包装:颤振/cupertino.dart”;
导入“dart:io”;
void main(){
runApp(MaterialApp(home:MyApp());
}
类MyApp扩展了StatefulWidget{
@凌驾
_MyAppState createState()=>\u MyAppState();
}
类MyAppState扩展了状态{
bool_isLoading=false;
bool\u下载=错误;
文件梳理图像;
字符串_languageDropdownValue;
bool-isError=false;
列表_语言=[
{'code':'en','value':'English'},
{'code':'fr','value':'French'},
];
@凌驾
小部件构建(构建上下文){
退货(
儿童:中心(
child:\u已下载
?图标按钮(
对齐:对齐.center,
填充:边集。对称(水平:0),
图标:图标(
Icons.open_in_new,
尺寸:45.0,
颜色:颜色。绿色,
),
已按下:(){
打印(“打开按钮按下”);
})
:_isLoading
?循环压缩机指示器(
valueColor:AlwaysStoppedAnimation(颜色.绿色),
)
:图标按钮(
对齐:对齐.center,
填充:边集。对称(水平:0),
图标:图标(
Icons.download_四舍五入,
尺寸:45.0,
颜色:颜色。绿色,
),
已按下:(){
打印(“按下下载按钮”);
显示对话框(
上下文:上下文,
生成器:(上下文){
返回状态生成器(
生成器:(上下文,状态设置器setState){
返回下载屏幕(
callbackFunction:alertDialogCallback,
下拉功能:alertDialogDropdown,
伊瑟罗:伊瑟罗,
语言:_语言,
languageDropdownValue:\u languageDropdownValue,
);
});
},
);
}),
),
);
}
字符串alertDialogDropdown(字符串newValue){
设置状态(){
_languageDropdownValue=新值;
});
返回新值;
}
alertDialogCallback(){
if(_languageDropdownValue==null | | | _languageDropdownValue.isEmpty){
设置状态(){
isError=真;
});
}否则{
设置状态(){
isError=错误;
startDownload();
});
}
}
void startDownload()异步{
打印(“所选语言为:$\u languageDropdownValue”);
Navigator.pop(上下文);
打印(“开始下载”);
设置状态(()=>\u下载=true);
}
}
类DownloadScreen扩展了无状态小部件{
下载屏幕(
{@required this.callback函数,
@需要此.dropdown函数,
@需要这个。isError,
@这是必需的。语言,
@需要此参数。languageDropdownValue});
final函数callbackFunction;
最终函数下拉函数;
最终字符串语言DropDownValue;
最终布尔伊瑟罗;
最后清单语言;
@凌驾
小部件构建(构建上下文){
返回警报对话框(
contentPadding:EdgeInsets.fromLTRB(24,24,24,14),
标题:文本(“确认购买”),
内容:专栏(
crossAxisAlignment:crossAxisAlignment.start,
mainAxisAlignment:mainAxisAlignment.start,
mainAxisSize:mainAxisSize.min,
儿童:[
Text('请选择指南语言:'),
灵活的(
子项:DropdownButtonFormField(
isExpanded:错,
是的,
dropdownColor:Colors.white,
value:languageDropdownValue,
提示:文本(
“首选语言”,
样式:TextStyle(颜色:Colors.grey),
),
项目:语言.map((map){
返回下拉菜单项(
值:映射['code'],
子:文本(
映射['value'],
溢出:TextOverflow.省略号,
),
);
}).toList(),
onChanged:(字符串newValue)=>dro
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:io';

void main() {
  runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isLoading = false;
  bool _downloaded = false;

  File cardImage;

  String _languageDropdownValue;

  bool isError = false;

  List<Map<String, String>> _languages = [
    {'code': 'en', 'value': 'English'},
    {'code': 'fr', 'value': 'French'},
  ];

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: _downloaded
            ? IconButton(
                alignment: Alignment.center,
                padding: EdgeInsets.symmetric(horizontal: 0),
                icon: Icon(
                  Icons.open_in_new,
                  size: 45.0,
                  color: Colors.green,
                ),
                onPressed: () {
                  print('Open button pressed');
                })
            : _isLoading
                ? CircularProgressIndicator(
                    valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
                  )
                : IconButton(
                    alignment: Alignment.center,
                    padding: EdgeInsets.symmetric(horizontal: 0),
                    icon: Icon(
                      Icons.download_rounded,
                      size: 45.0,
                      color: Colors.green,
                    ),
                    onPressed: () {
                      print('Download button pressed');
                      showDialog(
                        context: context,
                        builder: (context) {
                          return StatefulBuilder(
                              builder: (context, StateSetter setInnerState) {
                            return DownloadScreen(
                              callbackFunction: () =>
                                  alertDialogCallback(setInnerState),
                              dropDownFunction: (value) =>
                                  alertDialogDropdown(value, setInnerState),
                              isError: isError,
                              languages: _languages,
                              languageDropdownValue: _languageDropdownValue,
                            );
                          });
                        },
                      ).then((value) => _languageDropdownValue = null);
                    }),
      ),
    );
  }

  String alertDialogDropdown(String newValue, StateSetter setInnerState) {
    setInnerState(() {
      _languageDropdownValue = newValue;
      isError = false;
    });
    return newValue;
  }

  alertDialogCallback(StateSetter setInnerState) {
    if (_languageDropdownValue == null || _languageDropdownValue.isEmpty) {
      setInnerState(() {
        isError = true;
      });
    } else {
      setInnerState(() {
        isError = false;
        startDownload();
      });
    }
  }

  void startDownload() async {
    print('selected language is: $_languageDropdownValue');
    Navigator.pop(context);
    print('start download');
    setState(() => _downloaded = true);
  }
}

class DownloadScreen extends StatelessWidget {
  DownloadScreen(
      {@required this.callbackFunction,
      @required this.dropDownFunction,
      @required this.isError,
      @required this.languages,
      @required this.languageDropdownValue});

  final Function callbackFunction;
  final Function dropDownFunction;
  final String languageDropdownValue;
  final bool isError;
  final List<Map<String, String>> languages;

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      contentPadding: EdgeInsets.fromLTRB(24, 24, 24, 14),
      title: Text('Confirm purchase'),
      content: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('Please select the guide language:'),
          Flexible(
            child: DropdownButtonFormField(
              isExpanded: false,
              isDense: true,
              dropdownColor: Colors.white,
              value: languageDropdownValue,
              hint: Text(
                'Preferred Language',
                style: TextStyle(color: Colors.grey),
              ),
              items: languages.map((map) {
                return DropdownMenuItem(
                  value: map['code'],
                  child: Text(
                    map['value'],
                    overflow: TextOverflow.ellipsis,
                  ),
                );
              }).toList(),
              onChanged: (String newValue) => dropDownFunction(newValue),
              decoration: InputDecoration(
                filled: true,
                fillColor: Colors.white,
                labelStyle: TextStyle(color: Colors.grey),
                hintStyle: TextStyle(color: Colors.grey),
                errorStyle: TextStyle(fontSize: 17.0),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(10),
                  ),
                  borderSide: BorderSide.none,
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: BorderSide(color: Colors.blue, width: 2),
                  borderRadius: BorderRadius.all(
                    Radius.circular(10),
                  ),
                ),
              ),
            ),
          ),
          isError
              ? Center(
                  child: Padding(
                    padding: const EdgeInsets.only(bottom: 8.0),
                    child: Text(
                      'Please select a language',
                      style: TextStyle(
                        color: Colors.red,
                      ),
                    ),
                  ),
                )
              : Container(),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 20.0),
            child: Text('Are you sure you want to purchase this audio guide?'),
          ),
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.max,
            children: [
              ElevatedButton(
                onPressed: callbackFunction,
                child: Text('Yes'),
              ),
              SizedBox(
                width: 40,
              ),
              ElevatedButton(
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
                child: Text('No'),
                style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.blue),
                ),
              ),
            ],
          )
        ],
      ),
    );
  }
}
          showDialog(
                    context: context,
                    builder: (context) {
                      return StatefulBuilder(
                          builder: (context, StateSetter setInnerState) {
                        return DownloadScreen(
                          callbackFunction: () => alertDialogCallback(setInnerState),
                          dropDownFunction: (value) => alertDialogDropdown(value, setInnerState),
                          isError: isError,
                          languages: _languages,
                          languageDropdownValue: _languageDropdownValue,
                        );
                      });
                    },
                  );
String alertDialogDropdown(String newValue, StateSetter setInnerState) {
    setInnerState(() { //use this because calling setState here is calling _MyAppState's state
      _languageDropdownValue = newValue;
    });
    return newValue;
}


alertDialogCallback(StateSetter setInnerState) {
    if (_languageDropdownValue == null || _languageDropdownValue.isEmpty) {
      setInnerState(() {
        isError = true;
      });
    } else {
      setInnerState(() {
        isError = false;
        startDownload();
      });
    }
}
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:io';

void main() {
  runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isLoading = false;
  bool _downloaded = false;
  DownloadScreen downloadScreen;

  File cardImage;

  String _languageDropdownValue;

  bool isError = false;

  List<Map<String, String>> _languages = [
    {'code': 'en', 'value': 'English'},
    {'code': 'fr', 'value': 'French'},
  ];


  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: _downloaded
            ? IconButton(
            alignment: Alignment.center,
            padding: EdgeInsets.symmetric(horizontal: 0),
            icon: Icon(
              Icons.open_in_new,
              size: 45.0,
              color: Colors.green,
            ),
            onPressed: () {
              print('Open button pressed');
            })
            : _isLoading
            ? CircularProgressIndicator(
          valueColor: AlwaysStoppedAnimation<Color>(Colors.green),
        )
            : IconButton(
            alignment: Alignment.center,
            padding: EdgeInsets.symmetric(horizontal: 0),
            icon: Icon(
              Icons.download_rounded,
              size: 45.0,
              color: Colors.green,
            ),
            onPressed: () {
              print('Download button pressed');
              showDialog(
                context: context,
                builder: (context) {
                  return StatefulBuilder(
                      builder: (context, StateSetter setState) {
                        return downloadScreen = DownloadScreen(
                          alertDialogCallback,
                          alertDialogDropdown,
                          isError,
                          _languages,
                          _languageDropdownValue,
                        );
                      });
                },
              );
            }),
      ),
    );
  }

  String alertDialogDropdown(String newValue) {
    setState(() {
      _languageDropdownValue = newValue;
    });
    return newValue;
  }

  alertDialogCallback() {
    if (_languageDropdownValue == null || _languageDropdownValue.isEmpty) {
        isError = true;
        reloadDownloadScreen(true);
    } else {
      setState(() {
        isError = false;
        startDownload();
      });
    }
  }

  void startDownload() async {
    print('selected language is: $_languageDropdownValue');
    Navigator.pop(context);
    print('start download');
    setState(() => _downloaded = true);
  }

  void reloadDownloadScreen(bool isError) {
    downloadScreen.refresh(isError);
  }
}

class DownloadScreen extends StatefulWidget {
  final Function alertDialogCallback;
  final Function alertDialogDropdown;
  final bool isError;
  final List<Map<String, String>> languages;
  _DownloadScreen _downloadScreen;

  final String languageDropdownValue;
  void refresh(bool isError){
    _downloadScreen.refresh(isError);
  }

  DownloadScreen(this.alertDialogCallback, this.alertDialogDropdown, this.isError, this.languages, this.languageDropdownValue);
  @override
  _DownloadScreen createState(){
    _downloadScreen = _DownloadScreen(
        callbackFunction: alertDialogCallback,
        dropDownFunction: alertDialogDropdown,
        isError: isError,
        languages: languages,
        languageDropdownValue: languageDropdownValue
    );
    return _downloadScreen;
  }
}

class _DownloadScreen extends State<DownloadScreen> {
  _DownloadScreen(
      {@required this.callbackFunction,
        @required this.dropDownFunction,
        @required this.isError,
        @required this.languages,
        @required this.languageDropdownValue
      });

  final Function callbackFunction;
  final Function dropDownFunction;
  final String languageDropdownValue;
  bool isError;
  final List<Map<String, String>> languages;

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      contentPadding: EdgeInsets.fromLTRB(24, 24, 24, 14),
      title: Text('Confirm purchase'),
      content: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisAlignment: MainAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('Please select the guide language:'),
          Flexible(
            child: DropdownButtonFormField(
              isExpanded: false,
              isDense: true,
              dropdownColor: Colors.white,
              value: languageDropdownValue,
              hint: Text(
                'Preferred Language',
                style: TextStyle(color: Colors.grey),
              ),
              items: languages.map((map) {
                return DropdownMenuItem(
                  value: map['code'],
                  child: Text(
                    map['value'],
                    overflow: TextOverflow.ellipsis,
                  ),
                );
              }).toList(),
              onChanged: (String newValue) => dropDownFunction(newValue),
              decoration: InputDecoration(
                filled: true,
                fillColor: Colors.white,
                labelStyle: TextStyle(color: Colors.grey),
                hintStyle: TextStyle(color: Colors.grey),
                errorStyle: TextStyle(fontSize: 17.0),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(10),
                  ),
                  borderSide: BorderSide.none,
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: BorderSide(color: Colors.blue, width: 2),
                  borderRadius: BorderRadius.all(
                    Radius.circular(10),
                  ),
                ),
              ),
            ),
          ),
          isError
              ? Center(
            child: Padding(
              padding: const EdgeInsets.only(bottom: 8.0),
              child: Text(
                'Please select a language',
                style: TextStyle(
                  color: Colors.red,
                ),
              ),
            ),
          )
              : Container(),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 20.0),
            child: Text('Are you sure you want to purchase this audio guide?'),
          ),
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.max,
            children: [
              ElevatedButton(
                onPressed: callbackFunction,
                child: Text('Yes'),
              ),
              SizedBox(
                width: 40,
              ),
              ElevatedButton(
                onPressed: () {
                  Navigator.of(context).pop(false);
                },
                child: Text('No'),
                style: ButtonStyle(
                  backgroundColor: MaterialStateProperty.all(Colors.blue),
                ),
              ),
            ],
          )
        ],
      ),
    );
  }

  void refresh(bool isError) {setState(() {
    this.isError = isError;
  });}
}