Благодаря некоторой помощи от Овидиу я нашел хороший ответ. Я решил за go Provider
в пользу стати c класса. Я думаю, что реализация проще. Кроме того, я также заставил его показывать SnackBar
на новой странице (с новой Scaffold
), если она открыта.
Все, что вам нужно сделать для ее реализации, это import
MScaffold.dart
и измените ваши Scaffold
s на MScaffold
s.
Я считаю этот метод очень удобным, поэтому он может помочь другим людям, которые также ищут простой способ показать SnackBar
независимо от того, какой Scaffold
отображается в данный момент.
Вот страница презентации:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'MScaffold.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Snackbar manager',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Snackbar manager'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return MScaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FloatingActionButton(
heroTag: 0,
child: Icon(Icons.add_circle_outline),
onPressed: () {
ShowSnackBar().showText("You were on page 1");
},
),
FloatingActionButton(
heroTag: 1,
child: Icon(Icons.remove_circle_outline),
onPressed: () {
ShowSnackBar().hide();
},
),
FloatingActionButton(
heroTag: 2,
child: Icon(Icons.add),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SecondScaffold();
}));
},
),
],
),
);
}
}
class SecondScaffold extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MScaffold(
appBar: AppBar(
title: Text("Page 2"),
),
body: Center(),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FloatingActionButton(
heroTag: 0,
child: Icon(Icons.add_circle_outline),
onPressed: () {
ShowSnackBar().show(
SnackBar(
content: Text("You were on page 2"),
),
);
},
),
FloatingActionButton(
heroTag: 1,
child: Icon(Icons.remove_circle_outline),
onPressed: () {
ShowSnackBar().hide();
},
),
FloatingActionButton(
heroTag: 2,
child: Icon(Icons.remove),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
);
}
}
Здесь MScaffold.dart
:
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class ShowSnackBar extends ChangeNotifier {
SnackBar currentSnackBar;
int lastHideTime = -1; //in millisecondsSinceEpoch
String _msg;
bool isSnackBarVisible = false;
static final _thisClass = ShowSnackBar._internal();
ShowSnackBar._internal();
factory ShowSnackBar() {
return _thisClass;
}
ChangeNotifier showNotifier = ChangeNotifier();
ChangeNotifier hideNotifier = ChangeNotifier();
showText(String inputMsg) {
_msg = inputMsg;
currentSnackBar = SnackBar(content: Text(_msg));
isSnackBarVisible = true;
showNotifier.notifyListeners();
}
show(SnackBar inputSnackBar) {
currentSnackBar = inputSnackBar;
isSnackBarVisible = true;
showNotifier.notifyListeners();
}
hide() {
hideNotifier.notifyListeners();
}
}
class MScaffold extends Scaffold {
ValueKey key;
var appBar;
var body;
var floatingActionButton;
var floatingActionButtonLocation;
var floatingActionButtonAnimator;
var persistentFooterButtons;
var drawer;
var endDrawer;
var bottomNavigationBar;
var bottomSheet;
var backgroundColor;
var resizeToAvoidBottomPadding;
var resizeToAvoidBottomInset;
var primary;
var drawerDragStartBehavior;
var extendBody;
var extendBodyBehindAppBar;
var drawerScrimColor;
var drawerEdgeDragWidth;
MScaffold({
this.key,
this.appBar,
this.body,
this.floatingActionButton,
this.floatingActionButtonLocation,
this.floatingActionButtonAnimator,
this.persistentFooterButtons,
this.drawer,
this.endDrawer,
this.bottomNavigationBar,
this.bottomSheet,
this.backgroundColor,
this.resizeToAvoidBottomPadding,
this.resizeToAvoidBottomInset,
this.primary = true,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.extendBody = false,
this.extendBodyBehindAppBar = false,
this.drawerScrimColor,
this.drawerEdgeDragWidth,
}) : assert(primary != null),
assert(extendBody != null),
assert(extendBodyBehindAppBar != null),
assert(drawerDragStartBehavior != null),
assert(
!((key!=null
&&key.value is Map<String,dynamic>)
&&key.value.length==1
&&key.value.containsKey('MScaffoldAutoKey')),
"The Key you use for MScaffold cannot be a Map object that contains only one index "
"named, 'MScaffoldAutoKey,' as this is reserved for MScaffold."
),
super(key: key) {
if (key == null) this.key = _autoKeyGen();
}
static List<Key> _autoKeys = [];
bool _usesAutoKey = false;
Key _autoKeyGen() {
_usesAutoKey = true;
Key retKey = ValueKey({'MScaffoldAutoKey': _autoKeys.length});
_autoKeys.add(retKey);
return retKey;
}
@override
MScaffoldState createState() {
return MScaffoldState(
key: key,
appBar: appBar,
body: body,
floatingActionButton: floatingActionButton,
floatingActionButtonLocation: floatingActionButtonLocation,
floatingActionButtonAnimator: floatingActionButtonAnimator,
persistentFooterButtons: persistentFooterButtons,
drawer: drawer,
endDrawer: endDrawer,
bottomNavigationBar: bottomNavigationBar,
bottomSheet: bottomSheet,
backgroundColor: backgroundColor,
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
primary: primary,
drawerDragStartBehavior: drawerDragStartBehavior,
extendBody: extendBody,
extendBodyBehindAppBar: extendBodyBehindAppBar,
drawerScrimColor: drawerScrimColor,
drawerEdgeDragWidth: drawerEdgeDragWidth,
autoKeys: _usesAutoKey ? _autoKeys : null,
);
}
}
class MScaffoldState extends ScaffoldState {
Key key;
var appBar;
var body;
var floatingActionButton;
var floatingActionButtonLocation;
var floatingActionButtonAnimator;
var persistentFooterButtons;
var drawer;
var endDrawer;
var bottomNavigationBar;
var bottomSheet;
var backgroundColor;
var resizeToAvoidBottomPadding;
var resizeToAvoidBottomInset;
var primary;
var drawerDragStartBehavior;
var extendBody;
var extendBodyBehindAppBar;
var drawerScrimColor;
var drawerEdgeDragWidth;
var autoKeys;
MScaffoldState({
this.key,
this.appBar,
this.body,
this.floatingActionButton,
this.floatingActionButtonLocation,
this.floatingActionButtonAnimator,
this.persistentFooterButtons,
this.drawer,
this.endDrawer,
this.bottomNavigationBar,
this.bottomSheet,
this.backgroundColor,
this.resizeToAvoidBottomPadding,
this.resizeToAvoidBottomInset,
this.primary = true,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.extendBody = false,
this.extendBodyBehindAppBar = false,
this.drawerScrimColor,
this.drawerEdgeDragWidth,
this.autoKeys,
}) : assert(primary != null),
assert(extendBody != null),
assert(extendBodyBehindAppBar != null),
assert(drawerDragStartBehavior != null);
Function() _listenerShow;
Function() _listenerHide;
@override
void initState() {
super.initState();
_listenerShow = () {
if (mounted) {
Scaffold.of(_scaffoldContext)
.showSnackBar(ShowSnackBar().currentSnackBar)
.closed
.then((SnackBarClosedReason reason) {
ShowSnackBar().isSnackBarVisible = false;
ShowSnackBar().lastHideTime = DateTime.now().millisecondsSinceEpoch;
});
}
};
_listenerHide = () {
if (mounted) {
Scaffold.of(_scaffoldContext).hideCurrentSnackBar();
}
};
Future.microtask(() {
if (ShowSnackBar().isSnackBarVisible) _listenerShow();
ShowSnackBar().showNotifier.addListener(_listenerShow);
ShowSnackBar().hideNotifier.addListener(_listenerHide);
});
}
@override
dispose() {
ShowSnackBar().showNotifier?.removeListener(_listenerShow);
ShowSnackBar().hideNotifier?.removeListener(_listenerHide);
autoKeys?.remove(key);
super.dispose();
}
BuildContext _scaffoldContext;
@override
Widget build(BuildContext context) {
return Scaffold(
key: key,
appBar: appBar,
body: Builder(
builder: (context) {
_scaffoldContext = context;
return body;
},
),
floatingActionButton: floatingActionButton,
floatingActionButtonLocation: floatingActionButtonLocation,
floatingActionButtonAnimator: floatingActionButtonAnimator,
persistentFooterButtons: persistentFooterButtons,
drawer: drawer,
endDrawer: endDrawer,
bottomNavigationBar: bottomNavigationBar,
bottomSheet: bottomSheet,
backgroundColor: backgroundColor,
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
primary: primary,
drawerDragStartBehavior: drawerDragStartBehavior,
extendBody: extendBody,
extendBodyBehindAppBar: extendBodyBehindAppBar,
drawerScrimColor: drawerScrimColor,
drawerEdgeDragWidth: drawerEdgeDragWidth,
);
}
}