从 AlertDialog 中调用 SnackBar
Posted
技术标签:
【中文标题】从 AlertDialog 中调用 SnackBar【英文标题】:Call SnackBar from within an AlertDialog 【发布时间】:2020-07-20 22:28:28 【问题描述】:当用户点击删除员工时,会弹出一个AlertDialog来警告用户。
如果用户确认删除,则 AlertDialog 消失,并且在 Scaffold 的底部应该出现一个带有 Undo 功能的 SnackBar。
问题:
当我在 AlertDialog 类中实现 SnackBar 方法 showSnackBar(context, index, employee) 时,我收到以下错误:
在处理手势时抛出了以下断言:
使用不包含 Scaffold 的上下文调用 Scaffold.of()。
showDeleteDialog(BuildContext context, Employee employee, int index)
showDialog(
context: context,
builder: (context) => AlertDialog(
title:
Text('Are you sure you want to delete: $employee.name ?'),
actions: <Widget>[
Row(
children: <Widget>[
FlatButton(
child: Text('Yes'),
onPressed: ()
DatabaseProvider.db.deleteEmployee(employee.id).then(
(_) => BlocProvider.of<EmployeeBloc>(context)
.add(DeleteEmployee(index)));
Navigator.pop(context,employee);
showSnackBar(context, index, employee);
),
FlatButton(
child: Text('No!'),
onPressed: () => Navigator.pop(context)),
],
)
],
));
相反,当我确认删除时,我认为我可以从 showDeleteDialog 返回一个员工。当结果不为空时,我应该显示 SnackBar。我尝试使用 Future/Async 来实现这一点,但没有成功。
onPressed: () async
Employee deletedEmployee = await showDeleteDialog(context, employee, index);
await showSnackBar(context, index, deletedEmployee);
,
编辑:如果可能,我想避免使用 GlobalKey,因为我读到它不利于应用程序的性能。
【问题讨论】:
当您调用小吃店时,您似乎没有从脚手架传递 BuiltContext @LonelyWolf 完全正确。我不知道该怎么做。 尝试使用Builder()
Widget 包装您调用Snackbar 的小部件
【参考方案1】:
找到了解决办法,而且超级简单……
我只需要将 context 之一重命名为 dialogContext
showDeleteDialog(BuildContext context, Employee employee, int index)
showDialog(
context: context,
builder: (dialogContext) => AlertDialog(
title:
Text('Are you sure you want to delete: $employee.name ?'),
actions: <Widget>[
Row(
children: <Widget>[
FlatButton(
child: Text('Yes'),
onPressed: ()
DatabaseProvider.db.deleteEmployee(employee.id).then(
(_) => BlocProvider.of<EmployeeBloc>(dialogContext)
.add(DeleteEmployee(index)));
Navigator.pop(dialogContext);
showSnackBar(context, index, employee);
),
FlatButton(
child: Text('No!'),
onPressed: () => Navigator.pop(context)),
],
)
],
));
【讨论】:
【参考方案2】:正如错误所说的Scaffold.of() called with a context that does not contain a Scaffold.
,这意味着您传递给showSnackBar()
方法的当前context
在直接父级中不包含Scaffold
。
我们可以通过使用GlobalKey
来解决这个问题,并将其分配给Scaffold
。在您的有状态小部件中声明 global key
并将其作为键传递给您的 Scaffold
,如下所示:
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
....
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text(widget.title),
),
我在OK
按钮点击alertDialog
内的navigator.pop()
之后调用方法_showSnackBar()
,如下:
return AlertDialog(
title: Text('Not in stock'),
content: const Text('This item is no longer available'),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: ()
Navigator.of(context).pop();
_showSnackBar();
,
),
],
);
然后在_showSnackBar()
方法中,使用key显示snackbar,如下:
void _showSnackBar()
_scaffoldKey.currentState.showSnackBar(
SnackBar(
content: Text('Snackbar is displayed'),
));
使用这种方法,一旦您点击alertDialog
上的OK
按钮,对话框将关闭,您将看到小吃栏。您可能需要按照上面共享的代码自定义此设置。
希望这能回答您的问题并解决您的问题。
【讨论】:
虽然这似乎可行,但我找到了一个更简单的解决方案,同时避免了 GlobalKey 功能。我只需要重命名 AlertDialog 的上下文名称。 虽然这是正确的,但我想补充一点,有一个 known issue 在持续时间后不会隐藏小吃栏,所以 workaround 是调用Future.delayed(Duration(seconds: 1), () _scaffoldKey.currentState.hideCurrentSnackBar(); );
以上是关于从 AlertDialog 中调用 SnackBar的主要内容,如果未能解决你的问题,请参考以下文章
从 AlarmManger 弹出一个 AlertDialog
android 怎么使对话框(AlertDialog.Builder)自动消失
Android中activity定义的AlertDialog调用不弹出!
家庭记账本app进度之android中AlertDialog的相关应用以及对日期时间的相关操作(应用alertdialog使用的谈话框)