Flutter AlertDialog的颤振生成器未由父级中的SetState更新
我有一个父StatefulWidget和一个无状态Widget子部件,它返回一个AlertDialog对话框。当按下“绿色下载”按钮时,无状态小部件是从StatefulWidget中的生成器生成的。(在AlertDialog中确认后,完整代码将获取并存储数据) AlertDialog对话框中有一个DropDownButtonForm字段。我内置了自己的验证和错误消息,以确保关联的值不为null。(我无法获得DropdownButtonFormField的内置验证来显示整个错误消息,除非它被切断) 我不明白为什么我的AlertDialog没有被更新以显示回调SetState之后的错误消息,即使使用StatefulBuilder(我可能没有正确使用)。我尝试过使用StatefulWidget 电流输出: 当您按下AlertDialog中的yes按钮,但下拉值为null或空时,AlertDialog不会更新以在AlertDialog中显示错误消息的中心小部件。如果弹出AlertDialog并重新打开,它将显示错误消息 所需输出 当您按下AlertDialog中的yes按钮,但下拉值为null或空时,AlertDialog将更新,以在AlertDialog中显示显示错误消息的中心小部件 请问你能帮忙吗 可用于重新创建以下内容的代码:Flutter AlertDialog的颤振生成器未由父级中的SetState更新,flutter,dart,builder,flutter-alertdialog,Flutter,Dart,Builder,Flutter Alertdialog,我有一个父StatefulWidget和一个无状态Widget子部件,它返回一个AlertDialog对话框。当按下“绿色下载”按钮时,无状态小部件是从StatefulWidget中的生成器生成的。(在AlertDialog中确认后,完整代码将获取并存储数据) AlertDialog对话框中有一个DropDownButtonForm字段。我内置了自己的验证和错误消息,以确保关联的值不为null。(我无法获得DropdownButtonFormField的内置验证来显示整个错误消息,除非它被切断)
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;
});}
}