如何访问showModalBottomSheet中的Provided(Provider.of())值?

时间:2019-08-18 19:36:41

标签: flutter bloc flutter-provider

我在小部件树中有一个FloatingActionButton,它具有flutter_bloc中的BlocProvider。像这样:

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

我正在尝试在SomeBloc内使用BlocProvider.of<SomeBloc>(context)访问TheBottomSheet,但出现以下错误:

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软件包中的任何提供程序都具有相同的行为。

如何在BlocProvider.of<SomeBloc>(context)内部访问showModalBottomSheet

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

5 个答案:

答案 0 :(得分:3)

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

根据图片,对话框小部件位于MaterialApp下,因此这就是您使用错误上下文的原因

enter image description here

答案 1 :(得分:1)

InheritedWidgets(因此是Provider)的范围仅限于小部件树。在该树之外无法访问它们。

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

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

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

答案 2 :(得分:1)

showModalBottomSheet中的提供者(底部)

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

答案 3 :(得分:0)

您应该将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),
      ),
    );
  }
}

答案 4 :(得分:0)

我找到了一个解决方案,只需将您的showModalBottomSheet与StatefulBuilder一起返回,并使用您的模式表构建器的上下文传递给您的提供者即可。下面是我的代码的一部分:

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