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) =&gt; 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 返回列表

从 GitHub 克隆后无法运行 Flutter 项目

无法从 Firestore 文档中删除字段 (Flutter)

无法从 StreamBuilder (Flutter) 查询子集合

Flutter - 无法从 Webview 下载文件

Flutter 无法从剪贴板读取