Flutter:无法从 showModalBottomSheet 访问 Provider
Posted
技术标签:
【中文标题】Flutter:无法从 showModalBottomSheet 访问 Provider【英文标题】:Flutter: can't access Provider from showModalBottomSheet 【发布时间】:2020-12-28 06:50:58 【问题描述】:我无法从 FloatingActionButton 中的 showModalBottomSheet 访问定义在 Scaffold 上方的提供程序。
我已经这样定义了一个主页:
class HomePage extends StatelessWidget
@override
Widget build(BuildContext context)
return ChangeNotifierProvider(
create: (_) => MyProvider(),
builder: (context, _)
return Scaffold(
body: Consumer<MyProvider>(
builder: (context, provider, _)
return Text(provider.mytext); // this works fine
),
floatingActionButton: MyFAB(), // here is the problem
);
)
这是 MyFAB:
class MyFAB extends StatefulWidget
@override
_MyFABState createState() => _MyFABState();
class _MyFABState extends State<MyFAB>
@override
Widget build(BuildContext context)
return FloatingActionButton(
...
onPressed: () => show(),
);
void show()
showModalBottomSheet(
...
context: context,
builder: (BuildContext context)
return Wrap(
children: [
...
FlatButton(
onPressed: Provider.of<MyProvider>(context, listen: false).doSomething(); //Can't do this
Navigator.pop(context);
)
],
);
);
错误:在此 BottomSheet 小部件上方找不到正确的 Provider
【问题讨论】:
您是否尝试过传递上下文(从build
方法收到的上下文)而不是使用_MyFABState
实例的context
?
@GuilhermeMatuella 你是指 HomePage 小部件中 build 方法的上下文吗?
不,_MyFabState
中的 build
方法中的 BuildContext
。你创建你的FloatingActionButton
【参考方案1】:
通过将提供程序置于MaterialApp
上方进行修复,如here 所述。
底页在材料应用程序的根目录中创建。如果在材料应用程序下方声明了提供者,则底部表无法访问它,因为提供者不是小部件树中底部表的祖先。
下面的屏幕截图显示了一个小部件树:整个应用程序在 Wrapper
内,底部工作表未在 Wrapper
内创建。它被创建为MaterialApp
的另一个子元素(在本例中具有根元素Container
)。
对于您的情况:
// main.dart
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return ChangeNotifierProvider(
create: (_) => MyProvider(),
builder: (context, _)
return MaterialApp(
home: HomePage(),
);
,
);
// home_page.dart
class HomePage extends StatelessWidget
@override
Widget build(BuildContext context)
return Scaffold(
floatingActionButton: MyFAB()
);
【讨论】:
【参考方案2】:这是由于传递了错误的上下文引起的。将您的 FAB 包装到 Builder 小部件并将其作为 builder 属性传递。这将采用一个新的上下文并将其传递给 showModalBottomSheet。也可以onPressed: show
,更简洁。
class HomePage extends StatelessWidget
@override
Widget build(BuildContext context)
return ChangeNotifierProvider(
create: (_) => MyProvider(),
builder: (context, _)
return Scaffold(
body: Consumer<MyProvider>(
builder: (context, provider, _)
return Text(provider.mytext); // this works fine
),
floatingActionButton: MyFAB(context), // here is the problem
);
)
class MyFAB extends StatefulWidget
@override
_MyFABState createState() => _MyFABState();
class _MyFABState extends State<MyFAB>
@override
Widget build(BuildContext context)
return FloatingActionButton(
...
onPressed: (context) => show(context),
);
void show(ctx)
showModalBottomSheet(
...
context: ctx,
builder: (BuildContext context)
return Wrap(
children: [
...
FlatButton(
onPressed: ()
Provider.of<MyProvider>(ctx, listen: false).doSomething(); //Can't do this
Navigator.pop(ctx)
;
)
],
);
);
【讨论】:
我试过floatingActionButton: Builder(builder: (context) => MyFAB())
,但它不起作用。我收到同样的错误
@Fabio 我在示例代码中进行了编辑。您需要以某种方式将所需的上下文传递给您的 show 函数。这应该有效。如果没有,请分享您的整个代码,我将对其进行编辑。我还修复了您的 FlatButton onPressed 属性。您所做的两件事必须在一个函数中并传递给按钮。
在 MyFAB 中没有任何构造函数的情况下,您是如何从 HomePage 传递上下文参数的?
我没有对此进行测试,因为大部分代码都不完整。如果您遇到错误,请尝试在您的主页中定义 show() 并将其传递给您的晶圆厂,而不是为晶圆厂创建一个全新的文件
我为 FAB 创建了一个新文件,因为它比这更复杂,但是,我只是将上下文从 HomePage 传递到 MyFAB 并且它可以工作【参考方案3】:
解决方案
主页:
class HomePage extends StatelessWidget
@override
Widget build(BuildContext context)
return ChangeNotifierProvider(
create: (_) => MyProvider(),
builder: (context, _)
return Scaffold(
body: Consumer<MyProvider>(
builder: (context, provider, _)
return Text(provider.mytext); // this works fine
),
floatingActionButton: MyFAB(context), // here is the problem
);
)
我的FAB:
class MyFAB extends StatefulWidget
final BuildContext ctx;
MyFAB(this.ctx)
@override
_MyFABState createState() => _MyFABState();
class _MyFABState extends State<MyFAB>
@override
Widget build(BuildContext context)
return FloatingActionButton(
...
onPressed: () => show(),
);
void show()
showModalBottomSheet(
...
context: context,
builder: (BuildContext context)
return Wrap(
children: [
...
FlatButton(
onPressed: Provider.of<MyProvider>(widget.ctx, listen: false).doSomething(); //Can't do this
Navigator.pop(context);
)
],
);
);
【讨论】:
以上是关于Flutter:无法从 showModalBottomSheet 访问 Provider的主要内容,如果未能解决你的问题,请参考以下文章
无法从 Flutter 中的 Firebase Firestore 返回列表
无法从 Firestore 文档中删除字段 (Flutter)