简体   繁体   English

Flutter:无法从 showModalBottomSheet 访问 Provider

[英]Flutter: can't access Provider from showModalBottomSheet

I can't access a provider defined above a Scaffold from showModalBottomSheet in the FloatingActionButton.我无法从 FloatingActionButton 中的 showModalBottomSheet 访问在脚手架上方定义的提供程序。

I've defined a HomePage like so:我像这样定义了一个主页:

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
        );
      }
    )
  }
}

And this is MyFAB:这是 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);
            )
          ],
        );
      }
    );
  }
}

Error: Could not find the correct Provider<MyProvider above this BottomSheet Widget.错误:无法在此 BottomSheet 小部件上方找到正确的 Provider<MyProvider。

Fixed by placing the provider above MaterialApp , as described here .通过将提供者置于MaterialApp上来修复,如here所述。

Bottom sheets are created at the root of the material app.底部工作表是在材料应用程序的根部创建的。 If a prodiver is declared below the material app, a bottom sheet cannot access it because the provider is not an ancestor of the bottom sheet in the widget tree.如果在材料应用程序下方声明了一个提供者,则底部工作表无法访问它,因为提供者不是小部件树中底部工作表的祖先。

The screenshot below shows a widget tree: the whole app is inside Wrapper and the bottom sheet is not created inside Wrapper .下面的屏幕截图显示了一个小部件树:整个应用程序都在Wrapper内部,底部工作表不是在Wrapper内部创建的。 It is created as another child of MaterialApp (with a root element Container in this case).它被创建为MaterialApp另一个子元素(在本例中为根元素Container )。

小部件树

For your case:对于您的情况:

// 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()
    );
  }
}

This is caused by passing it the wrong context.这是由于将错误的上下文传递给它造成的。 Wrap your FAB to a Builder widget and pass it as builder property.将您的 FAB 包装到 Builder 小部件并将其作为构建器属性传递。 This will take a new context and pass it to showModalBottomSheet.这将采用一个新的上下文并将其传递给 showModalBottomSheet。 Also, you can do onPressed: show , it's more concise.另外,你可以做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)
              };
            )
          ],
        );
      }
    );
  }
}

SOLUTION解决方案

HomePage:主页:

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
        );
      }
    )
  }
}

MyFAB:我的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);
            )
          ],
        );
      }
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM