Open SnackBar inside函数发送到AppBar
Open SnackBar inside function sent to AppBar
我有一个带有表单的页面。一旦用户点击保存,它应该显示一个 SnackBar。保存按钮在一个单独的自定义 AppBar 小部件中(在一个单独的文件中),它有 2 个函数是从带有表单的页面发送的。 AppBar 被分开用于可重复使用的目的。
我试过使用 Builder 方法,但它不起作用。然后我用了Global Key的方法,它不会报错,但是还是没有SnackBar。
import 'package:flutter/material.dart';
import '../models/author.dart';
import '../widgets/edit_app_bar.dart';
class AuthorEditPage extends StatefulWidget {
static const PAGE_TITLE = 'Edit Author';
static const ROUTE_NAME = '/author-edit';
@override
_AuthorEditPageState createState() => _AuthorEditPageState();
}
class _AuthorEditPageState extends State<AuthorEditPage> {
@override
Widget build(BuildContext context) {
final _operation = ModalRoute.of(context).settings.arguments as String;
final GlobalKey<ScaffoldState> _scaffoldKey =
new GlobalKey<ScaffoldState>();
Author _initialize() {
return Author(
id: null,
name: 'Test',
nameOther: null,
facebook: null,
website: null,
lastUpdated: DateTime.now().toIso8601String(),
);
}
void _displaySnackBar(Author author) {
_scaffoldKey.currentState.showSnackBar(
SnackBar(
content: Text(
'Author: ${author.name} added',
),
),
);
}
return Scaffold(
key: _scaffoldKey,
appBar: EditAppBar(
title: AuthorEditPage.PAGE_TITLE,
saveAndAddNew: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
if (result) {
_displaySnackBar(author);
setState(() {});
}
},
save: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
if (result) {
_displaySnackBar(author);
Navigator.of(context).pop();
}
},
),
body: null,
);
}
}
自定义应用栏
import 'package:flutter/material.dart';
class EditAppBar extends StatelessWidget with PreferredSizeWidget {
EditAppBar({
Key key,
@required this.title,
@required this.saveAndAddNew,
@required this.save,
}) : super(key: key);
final String title;
final Function saveAndAddNew;
final Function save;
@override
Widget build(BuildContext context) {
return AppBar(
title: Text(
title,
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.add,
),
onPressed: saveAndAddNew,
),
IconButton(
icon: Icon(
Icons.save,
),
onPressed: save,
),
],
);
}
@override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
}
非常感谢help/guidance!
另一种不需要您使用必须具有脚手架的 snackbar 的快速方法是使用名为 Flushbar 的包。它真的很简单,消除了所有样板代码
Flushbar Link
问题是您在显示小吃栏然后弹出屏幕。您可以做的是在推送屏幕的页面上等待,然后在那里显示快餐栏。在 flutter 文档中有一个类似的用例示例:
_navigateAndDisplaySelection(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
查看完整示例here。
在自定义 AppBar 文件中,更改
final Function saveAndAddNew;
final Function save;
至
final void Function() saveAndAddNew;
final void Function() save;
Once the user clicks on Save, it should display a SnackBar
但是你的保存方法处理了脚手架和return到上一页,所以它不显示小吃栏(脚手架没有安装在下一帧)
save: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
if (result) {
_displaySnackBar(author);
Navigator.of(context).pop(); //disposing the Scaffold widget
}
},
如果你真的想显示一个脚手架,你应该使用你想要它显示的 ScaffoldWidget 的 GlobalKey(在上一页的这种情况下)。还要避免在构建方法中创建 GlobalKey,它会在您每次调用 setState 时创建一个新的。这是一个包含 2 个页面和 2 个 GloabalKey 的示例,第一页为第二页提供了 globalKey,因此它可以在需要时使用它。
class Page1 extends StatelessWidget{
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Center(
child: FlatButton(
child: Text('SecondPage'),
onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => AuthorEditPage(_scaffoldKey)))
)
)
);
}
}
class AuthorEditPage extends StatefulWidget {
static const PAGE_TITLE = 'Edit Author';
static const ROUTE_NAME = '/author-edit';
final GlobalKey<ScaffoldState> previousScaffold;
AuthorEditPage(this.previousScaffold);
@override
_AuthorEditPageState createState() => _AuthorEditPageState();
}
class _AuthorEditPageState extends State<AuthorEditPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); //initialize variables here
Author _initialize() {
return Author(
id: null,
name: 'Test',
nameOther: null,
facebook: null,
website: null,
lastUpdated: DateTime.now().toIso8601String(),
);
}
//give the GlobalKey of the scaffold you want to display the snackbar
void _displaySnackBar(Author author, GlobalKey<ScaffoldState> scaffold) {
scaffold?.currentState?.showSnackBar(
SnackBar(
content: Text(
'Author: ${author.name} added',
),
),
);
}
@override
Widget build(BuildContext context) {
final _operation = ModalRoute.of(context).settings.arguments as String; //This one requires the context so it's fine to be here
//Avoid creating objects or methods not related to the build method here, you can make them in the class
return Scaffold(
key: _scaffoldKey,
appBar: EditAppBar(
title: AuthorEditPage.PAGE_TITLE,
saveAndAddNew: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
print(result);
if (result) {
_displaySnackBar(author, _scaffoldKey);
setState(() {});
}
},
save: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
print(result);
if (result) {
_displaySnackBar(author, widget.previousScaffold); //I sue the globalKey of the scaffold of the first page
Navigator.of(context).pop();
}
},
),
body: null,
);
}
}
Flutter 2.0 稳定版
ScaffoldMessenger.of(context)
稳定版2.0
发布后,不再需要之前的逻辑
class AuthorEditPage extends StatefulWidget {
static const PAGE_TITLE = 'Edit Author';
static const ROUTE_NAME = '/author-edit';
//final GlobalKey<ScaffoldState> previousScaffold; not needed anymore
AuthorEditPage();
@override
_AuthorEditPageState createState() => _AuthorEditPageState();
}
class _AuthorEditPageState extends State<AuthorEditPage> {
//final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); //initialize variables here //not needed anymore
Author _initialize() {
return Author(
id: null,
name: 'Test',
nameOther: null,
facebook: null,
website: null,
lastUpdated: DateTime.now().toIso8601String(),
);
}
@override
Widget build(BuildContext context) {
final _operation = ModalRoute.of(context).settings.arguments as String; //This one requires the context so it's fine to be here
//Avoid creating objects or methods not related to the build method here, you can make them in the class
return Scaffold(
appBar: Builder( //Wrap it in a builder to get the context of the scaffold you're currently in
builder (context) {
return EditAppBar(
title: AuthorEditPage.PAGE_TITLE,
saveAndAddNew: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
print(result);
if (result) {
ScaffoldMessenger.maybeOf(context)?.showSnackBar(
SnackBar(
content: Text(
'Author: ${author.name} added',
),
),
);
setState(() {});
}
},
save: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
print(result);
if (result) {
// It should keep the snackbar across pages
ScaffoldMessenger.maybeOf(context)?.showSnackBar(
SnackBar(
content: Text(
'Author: ${author.name} added',
),
),
);
Navigator.of(context).pop();
}
},
);
}
),
body: null,
);
}
}
我有一个带有表单的页面。一旦用户点击保存,它应该显示一个 SnackBar。保存按钮在一个单独的自定义 AppBar 小部件中(在一个单独的文件中),它有 2 个函数是从带有表单的页面发送的。 AppBar 被分开用于可重复使用的目的。
我试过使用 Builder 方法,但它不起作用。然后我用了Global Key的方法,它不会报错,但是还是没有SnackBar。
import 'package:flutter/material.dart';
import '../models/author.dart';
import '../widgets/edit_app_bar.dart';
class AuthorEditPage extends StatefulWidget {
static const PAGE_TITLE = 'Edit Author';
static const ROUTE_NAME = '/author-edit';
@override
_AuthorEditPageState createState() => _AuthorEditPageState();
}
class _AuthorEditPageState extends State<AuthorEditPage> {
@override
Widget build(BuildContext context) {
final _operation = ModalRoute.of(context).settings.arguments as String;
final GlobalKey<ScaffoldState> _scaffoldKey =
new GlobalKey<ScaffoldState>();
Author _initialize() {
return Author(
id: null,
name: 'Test',
nameOther: null,
facebook: null,
website: null,
lastUpdated: DateTime.now().toIso8601String(),
);
}
void _displaySnackBar(Author author) {
_scaffoldKey.currentState.showSnackBar(
SnackBar(
content: Text(
'Author: ${author.name} added',
),
),
);
}
return Scaffold(
key: _scaffoldKey,
appBar: EditAppBar(
title: AuthorEditPage.PAGE_TITLE,
saveAndAddNew: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
if (result) {
_displaySnackBar(author);
setState(() {});
}
},
save: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
if (result) {
_displaySnackBar(author);
Navigator.of(context).pop();
}
},
),
body: null,
);
}
}
自定义应用栏
import 'package:flutter/material.dart';
class EditAppBar extends StatelessWidget with PreferredSizeWidget {
EditAppBar({
Key key,
@required this.title,
@required this.saveAndAddNew,
@required this.save,
}) : super(key: key);
final String title;
final Function saveAndAddNew;
final Function save;
@override
Widget build(BuildContext context) {
return AppBar(
title: Text(
title,
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.add,
),
onPressed: saveAndAddNew,
),
IconButton(
icon: Icon(
Icons.save,
),
onPressed: save,
),
],
);
}
@override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
}
非常感谢help/guidance!
另一种不需要您使用必须具有脚手架的 snackbar 的快速方法是使用名为 Flushbar 的包。它真的很简单,消除了所有样板代码 Flushbar Link
问题是您在显示小吃栏然后弹出屏幕。您可以做的是在推送屏幕的页面上等待,然后在那里显示快餐栏。在 flutter 文档中有一个类似的用例示例:
_navigateAndDisplaySelection(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
// After the Selection Screen returns a result, hide any previous snackbars
// and show the new result.
Scaffold.of(context)
..removeCurrentSnackBar()
..showSnackBar(SnackBar(content: Text("$result")));
}
查看完整示例here。
在自定义 AppBar 文件中,更改
final Function saveAndAddNew;
final Function save;
至
final void Function() saveAndAddNew;
final void Function() save;
Once the user clicks on Save, it should display a SnackBar
但是你的保存方法处理了脚手架和return到上一页,所以它不显示小吃栏(脚手架没有安装在下一帧)
save: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
if (result) {
_displaySnackBar(author);
Navigator.of(context).pop(); //disposing the Scaffold widget
}
},
如果你真的想显示一个脚手架,你应该使用你想要它显示的 ScaffoldWidget 的 GlobalKey(在上一页的这种情况下)。还要避免在构建方法中创建 GlobalKey,它会在您每次调用 setState 时创建一个新的。这是一个包含 2 个页面和 2 个 GloabalKey 的示例,第一页为第二页提供了 globalKey,因此它可以在需要时使用它。
class Page1 extends StatelessWidget{
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Center(
child: FlatButton(
child: Text('SecondPage'),
onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) => AuthorEditPage(_scaffoldKey)))
)
)
);
}
}
class AuthorEditPage extends StatefulWidget {
static const PAGE_TITLE = 'Edit Author';
static const ROUTE_NAME = '/author-edit';
final GlobalKey<ScaffoldState> previousScaffold;
AuthorEditPage(this.previousScaffold);
@override
_AuthorEditPageState createState() => _AuthorEditPageState();
}
class _AuthorEditPageState extends State<AuthorEditPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); //initialize variables here
Author _initialize() {
return Author(
id: null,
name: 'Test',
nameOther: null,
facebook: null,
website: null,
lastUpdated: DateTime.now().toIso8601String(),
);
}
//give the GlobalKey of the scaffold you want to display the snackbar
void _displaySnackBar(Author author, GlobalKey<ScaffoldState> scaffold) {
scaffold?.currentState?.showSnackBar(
SnackBar(
content: Text(
'Author: ${author.name} added',
),
),
);
}
@override
Widget build(BuildContext context) {
final _operation = ModalRoute.of(context).settings.arguments as String; //This one requires the context so it's fine to be here
//Avoid creating objects or methods not related to the build method here, you can make them in the class
return Scaffold(
key: _scaffoldKey,
appBar: EditAppBar(
title: AuthorEditPage.PAGE_TITLE,
saveAndAddNew: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
print(result);
if (result) {
_displaySnackBar(author, _scaffoldKey);
setState(() {});
}
},
save: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
print(result);
if (result) {
_displaySnackBar(author, widget.previousScaffold); //I sue the globalKey of the scaffold of the first page
Navigator.of(context).pop();
}
},
),
body: null,
);
}
}
Flutter 2.0 稳定版
ScaffoldMessenger.of(context)
稳定版2.0
class AuthorEditPage extends StatefulWidget {
static const PAGE_TITLE = 'Edit Author';
static const ROUTE_NAME = '/author-edit';
//final GlobalKey<ScaffoldState> previousScaffold; not needed anymore
AuthorEditPage();
@override
_AuthorEditPageState createState() => _AuthorEditPageState();
}
class _AuthorEditPageState extends State<AuthorEditPage> {
//final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); //initialize variables here //not needed anymore
Author _initialize() {
return Author(
id: null,
name: 'Test',
nameOther: null,
facebook: null,
website: null,
lastUpdated: DateTime.now().toIso8601String(),
);
}
@override
Widget build(BuildContext context) {
final _operation = ModalRoute.of(context).settings.arguments as String; //This one requires the context so it's fine to be here
//Avoid creating objects or methods not related to the build method here, you can make them in the class
return Scaffold(
appBar: Builder( //Wrap it in a builder to get the context of the scaffold you're currently in
builder (context) {
return EditAppBar(
title: AuthorEditPage.PAGE_TITLE,
saveAndAddNew: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
print(result);
if (result) {
ScaffoldMessenger.maybeOf(context)?.showSnackBar(
SnackBar(
content: Text(
'Author: ${author.name} added',
),
),
);
setState(() {});
}
},
save: () async {
Author author = _initialize();
bool result = await author.createUpdateDelete(_operation);
print(result);
if (result) {
// It should keep the snackbar across pages
ScaffoldMessenger.maybeOf(context)?.showSnackBar(
SnackBar(
content: Text(
'Author: ${author.name} added',
),
),
);
Navigator.of(context).pop();
}
},
);
}
),
body: null,
);
}
}