Flutter Dialog Context 注意事项
先来看一段代码:
Future<dynamic> _showDeleteDialog(
BuildContext context, UserProvider userProvider, PlayerData player) {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
actionsPadding:
const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
titleTextStyle: const TextStyle(
color: MyColors.styleBlack,
fontWeight: FontWeight.normal,
fontSize: 20),
title: Text(S.of(context).delete_player_or_not),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: Text(S.of(context).dialog_cancel,
style: const TextStyle(
color: MyColors.styleColor,
)),
),
TextButton(
onPressed: () async {
Navigator.pop(context, 'OK');
// AlertDialog 的 context 已经出栈,再使用会出错
LoadingDialog.show(context: context);
var success =
await userProvider.deletePlayer(playerId: player.id);
LoadingDialog.hide();
if (success) {
if (!mounted) return;
Navigator.pop(context);
}
},
child: Text(S.of(context).dialog_ok,
style: const TextStyle(
color: Colors.red,
)),
),
],
);
});
}
在这个例子中,显示调用 AlertDialog,假设按了确定,则弹出一个 LoadingDialog 访问 api。在这个过程中,LoadingDialog 还可以正常展示,但是无法隐藏,此时 context 为空。因为 Navigator.pop(context, 'OK')
已经把 AlertDialog 出栈,其对应的 context 也会 unmounted。
正确的做法是 Navigator.pop(context, 'OK')
之后的 context 均使用 AlertDialog 上一层的 context(即当前还 mounted 的 context)
Future<dynamic> _showDeleteDialog(
BuildContext context, UserProvider userProvider, PlayerData player) {
// 外层 context
var outsideContext = context;
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
actionsPadding:
const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
titleTextStyle: const TextStyle(
color: MyColors.styleBlack,
fontWeight: FontWeight.normal,
fontSize: 20),
title: Text(S.of(context).delete_player_or_not),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(context, 'Cancel'),
child: Text(S.of(context).dialog_cancel,
style: const TextStyle(
color: MyColors.styleColor,
)),
),
TextButton(
onPressed: () async {
Navigator.pop(context, 'OK');
// AlertDialog 的 context 已经出栈,需要使用上一层的 context
LoadingDialog.show(context: outsideContext);
var success =
await userProvider.deletePlayer(playerId: player.id);
LoadingDialog.hide();
if (success) {
if (!mounted) return;
Navigator.pop(outsideContext);
}
},
child: Text(S.of(context).dialog_ok,
style: const TextStyle(
color: Colors.red,
)),
),
],
);
});
}