0

我无法从 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<MyProvider。

4

3 回答 3

2

通过将提供程序放置在上面进行修复,如此MaterialApp所述。

底部工作表在材料应用程序的根目录中创建。如果在材料应用程序下方声明了提供程序,则底部工作表无法访问它,因为提供程序不是小部件树中底部工作表的祖先。

下面的屏幕截图显示了一个小部件树:整个应用程序在里面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()
    );
  }
}
于 2021-03-06T09:50:20.350 回答
0

解决方案

主页:

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 {
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);
            )
          ],
        );
      }
    );
  }
}
于 2020-09-09T20:43:51.673 回答
0

这是由于传递了错误的上下文引起的。将您的 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)
              };
            )
          ],
        );
      }
    );
  }
}
于 2020-09-09T19:54:35.513 回答