如何在扑动中刷新 AlertDialog?

目前,我有一个 AlertDialog和一个 IconButton。用户可以点击图标按钮,我有两种颜色为每次点击。问题是我需要关闭 AlertDialog 并重新打开以查看颜色图标的状态变化。我想在用户单击 IconButton 时立即更改它的颜色。

密码如下:

bool pressphone = false;
//....
new IconButton(
icon: new Icon(Icons.phone),
color: pressphone ? Colors.grey : Colors.green,
onPressed: () => setState(() => pressphone = !pressphone),
),
98335 次浏览

这是因为您需要将您的 AlertDialog放在它自己的 StatefulWidget中,并将所有的状态操作逻辑移动到那里的颜色上。

更新:

enter image description here

void main() => runApp(MaterialApp(home: Home()));


class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text('Open Dialog'),
onPressed: () {
showDialog(
context: context,
builder: (_) {
return MyDialog();
});
},
)));
}
}


class MyDialog extends StatefulWidget {
@override
_MyDialogState createState() => new _MyDialogState();
}


class _MyDialogState extends State<MyDialog> {
Color _c = Colors.redAccent;
@override
Widget build(BuildContext context) {
return AlertDialog(
content: Container(
color: _c,
height: 20.0,
width: 20.0,
),
actions: <Widget>[
FlatButton(
child: Text('Switch'),
onPressed: () => setState(() {
_c == Colors.redAccent
? _c = Colors.blueAccent
: _c = Colors.redAccent;
}))
],
);
}
}

在对话框中使用 StatueBuilder 来使用 setState,并且只在对话框中更新 Widgets。

showDialog(
context: context,
builder: (context) {
String contentText = "Content of Dialog";
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text("Title of Dialog"),
content: Text(contentText),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context),
child: Text("Cancel"),
),
TextButton(
onPressed: () {
setState(() {
contentText = "Changed Content of Dialog";
});
},
child: Text("Change"),
),
],
);
},
);
},
);

当前用于检索 Dialog I 的值

showDialog().then((val){
setState (() {});
print (val);
});

例子 第一幕

    onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AddDespesa();
}).then((val) {
setState(() {});
print(val);
}
);
}

第二幕

AlertDialog(
title: Text("Sucesso!"),
content: Text("Gasto resgristrado com sucesso"),
actions: <Widget>[
FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.pop(context, true);
},
),
],
);

将被印刷成真,

在 AlertDialog 的 content部分使用 StatefulBuilder。甚至 StatateBuilder 文档实际上也有一个带对话框的示例。

它所做的就是提供一个新的 背景SetState函数,以便在需要时重新构建。

示例代码:

showDialog(
context: context,
builder: (BuildContext context) {


int selectedRadio = 0; // Declare your variable outside the builder
    

return AlertDialog(
content: StatefulBuilder(  // You need this, notice the parameters below:
builder: (BuildContext context, StateSetter setState) {
return Column(  // Then, the content of your dialog.
mainAxisSize: MainAxisSize.min,
children: List<Widget>.generate(4, (int index) {
return Radio<int>(
value: index,
groupValue: selectedRadio,
onChanged: (int value) {
// Whenever you need, call setState on your variable
setState(() => selectedRadio = value);
},
);
}),
);
},
),
);
},
);

正如我提到的,ShowDialog 文档上是这么说的:

[ ... ]构建器返回的小部件与位置不共享上下文 这个 showDialog 最初是从。 < strong > 使用一个状态构建器或 如果对话框需要动态更新 .

,则自定义 StatuseWidget

首先,您需要使用 StatefulBuilder。然后我设置 _setState变量,甚至可以在 StatefulBuilder之外使用,以设置新的状态。

StateSetter _setState;
String _demoText = "test";


showDialog(
context: context,
builder: (BuildContext context) {


return AlertDialog(
content: StatefulBuilder(  // You need this, notice the parameters below:
builder: (BuildContext context, StateSetter setState) {
_setState = setState;
return Text(_demoText);
},
),
);
},
);

_ setState 与 setState 方法的使用方式相同,例如:

_setState(() {
_demoText = "new test text";
});

如果你通过视图模型将你的数据从 UI 中分离出来,并使用 ChangeNotifierProvider包,你需要像这样在调用对话框的小部件中包含你当前的模型:

showDialog(context: context, builder: (dialog) {
return ChangeNotifierProvider.value(
value: context.read<ViewModel>(),
child: CustomStatefulDialogWidget(),
);
},

请注意,可能有一个更干净的方法来做到这一点,但这为我工作。

关于 Provider: https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple的附加信息

showModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState /*You can rename this!*/) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(onPressed: () {
setState(() {
heightOfModalBottomSheet += 10;
});
}),
);
});
});

基于安德里斯的 回答

当对话框与父小部件共享相同的状态时,您可以覆盖父小部件的方法 setState 来调用 StatuseBuilder 的 setState,因此不需要调用 setState 两次。

StateSetter? _setState;


Dialog dialog = showDialog(
context: context,
builder: (BuildContext context) {


return AlertDialog(
content: StatefulBuilder(  // You need this, notice the parameters below:
builder: (BuildContext context, StateSetter setState) {
_setState = setState;
return Text(_demoText);
},
),
);
},
);


// set the function to null when dialo is dismiss.
dialogFuture.whenComplete(() => {_stateSetter = null});


@override
void setState(VoidCallback fn) {
// invoke dialog setState to refresh dialog content when need
_stateSetter?.call(fn);
super.setState(fn);
}

事实上,您可以使用 StatefullBuilder,但问题是,当您使用这个小部件时,您不能改变基本屏幕的状态!为了使用 setState,更喜欢导航到一个新的屏幕。

不确定这是否是最佳实践,但是在使用 最佳答案向对话框添加 state 之后,我通过包装 setState 函数解决了更新对话框状态和内容状态的问题:

IconButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, newSetState) { // Create a "new" state variable
return AlertDialog(
content: DropdownButton(
value: listItem.type,
items: allItems
onChanged: (value) {
newSetState(() {
setState(() {
// HERE SET THE STATE TWICE
// Once with the "new" state, once with the "old"
});
});
})
),
);
}
);
}
),