我正在尝试跟踪当前的Scaffold
(它们的BuildContext
),以创建一个应用程序范围的SnackBar
函数。当前,我正在创建一个class
,它显示一个Scaffold
并将其context
添加到另一个class
,后者管理当前正在运行的Scaffold
。但是,我没有成功,因为我目前的尝试有两个问题:
Scaffold
的dispose
的Scaffold
的BuildContext
中删除List
的Scaffold
而言,BuildContext
方法为时已晚,因此向我展示了Exception
,“Looking up a deactivated widget's ancestor is unsafe.
” 这是我目前的尝试:
main.dart
):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: (){
MScaffoldManager.showSnackbar();
},
),
FloatingActionButton(
heroTag: 1,
child:Icon(Icons.remove_circle_outline),
onPressed: (){
MScaffoldManager.hideSnackbar();
},
),
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: (){
MScaffoldManager.showSnackbar();
},
),
FloatingActionButton(
heroTag: 1,
child:Icon(Icons.remove_circle_outline),
onPressed: (){
MScaffoldManager.hideSnackbar();
},
),
FloatingActionButton(
heroTag: 2,
child:Icon(Icons.remove),
onPressed: (){
Navigator.of(context).pop();
},
),
],
),
);
}
}
library
class
es:MScaffoldManager
; MScaffold
;和MScaffoldState
:
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class MScaffoldManager{
static List<Map> scaffoldInformation = List();
static void addScaffold(context){
scaffoldInformation.add({'context':context});
print("Scaffold added:\n"+scaffoldInformation.toString());
}
static void removeScaffold(context){
Scaffold.of(context).hideCurrentSnackBar();
scaffoldInformation.remove({'context':context});
print("Scaffold removed:\n"+scaffoldInformation.toString());
}
static void showSnackbar(){
scaffoldInformation.forEach((v){
Scaffold.of(v['context']).showSnackBar(SnackBar(
content: Text("Snackbar works"),
));
});
}
static void hideSnackbar(){
scaffoldInformation.forEach((v){
Scaffold.of(v['context']).hideCurrentSnackBar();
});
}
}
class MScaffold extends StatefulWidget{
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;
MScaffold({
Key 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);
@override
State<StatefulWidget> 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,
);
}
}
class MScaffoldState extends State<MScaffold> {
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;
MScaffoldState({
Key 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);
@override
void initState() {
super.initState();
}
@override
dispose(){
MScaffoldManager.removeScaffold(_scaffoldContext);
super.dispose();
}
BuildContext _scaffoldContext;
@override
Widget build(BuildContext context) {
return Scaffold(
key: key,
appBar: appBar,
body: Builder(
builder: (context){
if(_scaffoldContext!=null)
MScaffoldManager.removeScaffold(_scaffoldContext);
_scaffoldContext = context;
MScaffoldManager.addScaffold(_scaffoldContext);
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,
);
}
}
承认它不能按原样工作,它似乎也有些冗长和困惑。我想做的就是简单地制作一个
Scaffold
class
,其功能类似于Scaffold
,但是与管理器class
一起使用,它可以跟踪所有Scaffold
的context
,因此无论什么页面,我都可以轻松显示SnackBar
消息用户开启。 最佳答案
我还没有亲自尝试过此代码,但是您如何创建要与ChangeNotifier
一起使用的Provider
并将其附加在MaterialApp
上方:
class MyErrorChangeNotifier extends ChangeNotifier {
String error;
setError(String error) {
this.error = error;
notifyListeners();
}
}
然后创建一个自定义的
Scaffold
,如果已安装SnackBar
,则每次调用setError
时都会显示Scaffold
:class MyScaffold extends Scaffold {
// TODO constructor
@override
ScaffoldState createState() => MyScaffoldState();
}
class MyScaffoldState extends ScaffoldState {
MyErrorChangeNotifier _myErrorCN;
Function() _listener;
@override
void initState() {
super.initState();
_listener = () {
if (mounted) {
showSnackBar(SnackBar(content: Text(_myErrorCN.error)));
}
};
Future.microtask(() {
_myErrorCN = Provider.of<MyErrorChangeNotifier>(context, listen: false)..addListener(_listener);
});
}
@override
void dispose() {
_myErrorCN?.removeListener(_listener);
super.dispose();
}
}
每当有这种使用案例时,请尝试使用提供程序考虑解决方案-将数据从上下文层次结构发送到ChangeNotifier,ChangeNotifier然后将数据从上下文层次结构发送回所有侦听它的小部件。