【问题标题】:How to access Provided (Provider.of()) value inside showModalBottomSheet?如何访问 showModalBottomSheet 中提供的 (Provider.of()) 值?
【发布时间】:2019-12-24 03:28:26
【问题描述】:

我在一个小部件树中有一个 FloatingActionButton,它有一个来自 flutter_blocBlocProvider。像这样的:

BlocProvider(
  builder: (context) {
    SomeBloc someBloc = SomeBloc();
    someBloc.dispatch(SomeEvent());

    return someBloc;
  },
  child: Scaffold(
    body: ...
    floatingActionButton: FloatingActionButton(
      onPressed: _openFilterSchedule,
      child: Icon(Icons.filter_list),
    ),
  )
);

打开一个模态底页:

void _openFilterSchedule() {
    showModalBottomSheet<void>(
      context: context,
      builder: (BuildContext context) {
        return TheBottomSheet();
      },
    );
  }

我正在尝试使用BlocProvider.of&lt;SomeBloc&gt;(context)TheBottomSheet 中访问SomeBloc,但出现以下错误:

BlocProvider.of() called with a context that does not contain a Bloc of type SomeBloc.

我尝试使用https://stackoverflow.com/a/56533611/2457045 中描述的解决方案,但仅适用于BottomSheet 而不适用于ModalBottomSheet


注意:这不限于BlocProviderflutter_blocprovider 包中的任何 Provider 都具有相同的行为。

如何在showModalBottomSheet 中访问BlocProvider.of&lt;SomeBloc&gt;(context)

如果无法做到这一点,如何使https://stackoverflow.com/a/56533611/2457045 解决方案适应模态底页?

【问题讨论】:

    标签: flutter bloc flutter-provider


    【解决方案1】:

    InheritedWidgets 以及提供者的范围都在小部件树中。无法在该树之外访问它们。

    问题是,使用showDialog 和类似功能,对话框位于不同的小部件树中——它可能无法访问所需的提供者。

    因此有必要在新的小部件树中添加所需的提供者:

    void myShowDialog() {
      final myModel = Provider.of<MyModel>(context, listen: false);
      showDialog(
        context: context,
        builder: (_) {
          return Provider.value(value: myModel, child: SomeDialog());
        },
      );
    }
    

    【讨论】:

    • 这个实现有什么需要担心的吗?提供 2 次似乎很奇怪。
    • @FlutterFirebase 没有。这是完全合乎逻辑和期望的
    • 但是 2 提供者不同吗?例如,两个提供者中的变量访问是否相同?我现在正在实施,如果我从新提供者调用方法,这似乎不是其他小部件树中的通知侦听器
    • 如果我这样做,它会显示Unhandled Exception: Error: Could not find the correct Provider&lt;Model&gt; above this Page Widget
    • 如何在 SomeDialog() 小部件中访问提供者值?
    【解决方案2】:

    您需要将 Provider 移到顶层(MaterialApp)

    根据图片,Dialog小部件在MaterialApp下,所以这就是你使用错误上下文的原因

    【讨论】:

      【解决方案3】:

      showModalBottomSheet 中的提供者(底部表)

      void myBottomSheet() {
        final myModel = Provider.of<MyModel>(context, listen: false);
        showModalBottomShee(
          context: context,
          builder: (_) {
            return ListenableProvider.value(
              value: myModel,
              child: Text(myModel.txtValue),
            );
          },
        );
      }
      

      【讨论】:

        【解决方案4】:

        您应该将 Scaffold 小部件及其子组件拆分为另一个 StatefulWidget

        来自单个小部件

        class MainScreen extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return BlocProvider(
              builder: (context) {
                SomeBloc someBloc = SomeBloc();
                someBloc.dispatch(SomeEvent());
                return someBloc;
              },
              child: Scaffold(
                body: ...
                floatingActionButton: FloatingActionButton(
                  onPressed: _openFilterSchedule,
                  child: Icon(Icons.filter_list),
                ),
              )
            );
          }
        }
        

        分成这两个小部件

        class MainScreen extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return BlocProvider(
              builder: (context) {
                SomeBloc someBloc = SomeBloc();
                someBloc.dispatch(SomeEvent());
                return someBloc;
              },
              child: Screen(),
            );
          }
        }
        

        和..

        class Screen extends StatelessWidget {
        
          void _openFilterSchedule() {
            showModalBottomSheet<void>(
              context: context,
              builder: (BuildContext context) {
                return TheBottomSheet();
              },
            );
          }
        
          @override
          Widget build(BuildContext context) {
            return Scaffold(
              body: ...
              floatingActionButton: FloatingActionButton(
                onPressed: _openFilterSchedule,
                child: Icon(Icons.filter_list),
              ),
            );
          }
        }
        

        【讨论】:

        • 我必须将 Screen 更改为 Stateful 才能使用 showModalBottomSheet,但它不起作用。在TheBottomSheet 中抛出相同的错误。
        【解决方案5】:

        我找到了一个解决方案,只需使用 StatefulBuilder 返回您的 showModalBottomSheet 并使用您的 modalsheet 构建器的上下文传递给您的提供商。下面是我的代码的 sn-p:

        Future<Widget> showModal(int qty, Product product) async {
            return await showModalBottomSheet(
                isScrollControlled: true,
                backgroundColor: Colors.transparent,
                context: context,
                builder: (BuildContext ctx) {
                  return StatefulBuilder(builder: (ctx, state) {
                     return Container(
                          child: RaisedButton(
                                  onPressed: () {
                                     Product prod = Product(product.id, 
                                                 product.sku, product.name, qty);
                                     Provider.of<CartProvider>(ctx, listen: 
                                                false).addCart(prod);}),);
            }
          }
        );
        }
        

        【讨论】:

          【解决方案6】:

          在处理 showModelBottomSheet 时遇到了同样的问题,因为它恰好在不同的(上下文)小部件树中工作,我必须将我的状态升级到应用程序的状态,以便我可以使用上下文访问我的提供程序。

          【讨论】:

            猜你喜欢
            • 2017-11-15
            • 2020-10-31
            • 2020-12-28
            • 2019-12-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-04-29
            • 2019-09-30
            相关资源
            最近更新 更多