如何访问 showModalBottomSheet 中提供的 (Provider.of()) 值?
How to access Provided (Provider.of()) value inside showModalBottomSheet?
我在小部件树中有一个 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),
),
)
);
打开模态底部 sheet:
void _openFilterSchedule() {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return TheBottomSheet();
},
);
}
我正在尝试使用 TheBottomSheet
中的 BlocProvider.of<SomeBloc>(context)
访问 SomeBloc
,但出现以下错误:
BlocProvider.of() called with a context that does not contain a Bloc of type SomeBloc.
我已尝试使用 中描述的解决方案,但仅适用于 BottomSheet
而不适用于 ModalBottomSheet
。
注意:这不限于 BlocProvider
或 flutter_bloc
。 provider 包中的任何 Provider 都具有相同的行为。
如何在 showModalBottomSheet
中访问 BlocProvider.of<SomeBloc>(context)
?
如果无法做到这一点,如何使 解决方案适应模态底部 Sheet?
您应该将 Scaffold 小部件及其子部件拆分为另一个 StatefulWidget
来自单个 Widget
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),
),
)
);
}
}
拆分成这两个widget
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),
),
);
}
}
InheritedWidgets 和 Provider 的范围都在小部件树中。无法在该树之外访问它们。
事实是,使用 showDialog
和类似的功能,对话框位于不同的小部件树中——它可能无法访问所需的提供程序。
因此有必要在新的小部件树中添加所需的提供程序:
void myShowDialog() {
final myModel = Provider.of<MyModel>(context, listen: false);
showDialog(
context: context,
builder: (_) {
return Provider.value(value: myModel, child: SomeDialog());
},
);
}
您需要将 Provider 移动到顶层(MaterialApp)
根据图片,对话框小部件位于 MaterialApp 下,所以这就是您使用错误上下文的原因
我找到了一个解决方案,只需 return 带有 StatefulBuilder 的 showModalBottomSheet 并使用模态表生成器的上下文传递给您的提供商。下面是我的代码片段:
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);}),);
}
}
);
}
提供商在 showModalBottomSheet
(Bottom-Sheet)
void myBottomSheet() {
final myModel = Provider.of<MyModel>(context, listen: false);
showModalBottomShee(
context: context,
builder: (_) {
return ListenableProvider.value(
value: myModel,
child: Text(myModel.txtValue),
);
},
);
}
在处理 showModelBottomSheet 时遇到了同样的问题,因为它恰好在不同的(上下文)小部件树中工作,所以我必须将我的状态升级到应用程序的状态,以便我可以使用上下文访问我的提供者。
TLDR:确保导入语句的大小写与项目的文件夹大小写匹配。
我在调试同样的错误时遇到了另一个怪癖。我有几个都在工作的提供程序,包括在 showModalBottomSheets 中,但是一个不工作。在梳理了整个小部件树之后,在没有发现任何差异的情况下,我发现我在 problem-child 通知程序的一个导入语句中将文件夹的首字母大写了。我认为这混淆了编译器并导致它抛出 Could not find the correct Provider above this widget
错误。
确保导入语句的大小写与文件夹名称匹配后,我的提供商问题就解决了。希望这会让一些人头疼。
没有找到添加多个提供值的明确解释,我想在这里分享以供参考。
await showMobileModals(
isDismissible: false,
context: context,
child: MultiProvider(
providers: [
Provider.value(
value: provided_one,
),
Provider.value(
value: provided_two,
),
Provider.value(
value: provided_three,
),
],
child: Container(),
),
);
我在小部件树中有一个 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),
),
)
);
打开模态底部 sheet:
void _openFilterSchedule() {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return TheBottomSheet();
},
);
}
我正在尝试使用 TheBottomSheet
中的 BlocProvider.of<SomeBloc>(context)
访问 SomeBloc
,但出现以下错误:
BlocProvider.of() called with a context that does not contain a Bloc of type SomeBloc.
我已尝试使用 BottomSheet
而不适用于 ModalBottomSheet
。
注意:这不限于 BlocProvider
或 flutter_bloc
。 provider 包中的任何 Provider 都具有相同的行为。
如何在 showModalBottomSheet
中访问 BlocProvider.of<SomeBloc>(context)
?
如果无法做到这一点,如何使
您应该将 Scaffold 小部件及其子部件拆分为另一个 StatefulWidget
来自单个 Widget
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),
),
)
);
}
}
拆分成这两个widget
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),
),
);
}
}
InheritedWidgets 和 Provider 的范围都在小部件树中。无法在该树之外访问它们。
事实是,使用 showDialog
和类似的功能,对话框位于不同的小部件树中——它可能无法访问所需的提供程序。
因此有必要在新的小部件树中添加所需的提供程序:
void myShowDialog() {
final myModel = Provider.of<MyModel>(context, listen: false);
showDialog(
context: context,
builder: (_) {
return Provider.value(value: myModel, child: SomeDialog());
},
);
}
您需要将 Provider 移动到顶层(MaterialApp)
根据图片,对话框小部件位于 MaterialApp 下,所以这就是您使用错误上下文的原因
我找到了一个解决方案,只需 return 带有 StatefulBuilder 的 showModalBottomSheet 并使用模态表生成器的上下文传递给您的提供商。下面是我的代码片段:
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);}),);
}
}
);
}
提供商在 showModalBottomSheet
(Bottom-Sheet)
void myBottomSheet() {
final myModel = Provider.of<MyModel>(context, listen: false);
showModalBottomShee(
context: context,
builder: (_) {
return ListenableProvider.value(
value: myModel,
child: Text(myModel.txtValue),
);
},
);
}
在处理 showModelBottomSheet 时遇到了同样的问题,因为它恰好在不同的(上下文)小部件树中工作,所以我必须将我的状态升级到应用程序的状态,以便我可以使用上下文访问我的提供者。
TLDR:确保导入语句的大小写与项目的文件夹大小写匹配。
我在调试同样的错误时遇到了另一个怪癖。我有几个都在工作的提供程序,包括在 showModalBottomSheets 中,但是一个不工作。在梳理了整个小部件树之后,在没有发现任何差异的情况下,我发现我在 problem-child 通知程序的一个导入语句中将文件夹的首字母大写了。我认为这混淆了编译器并导致它抛出 Could not find the correct Provider above this widget
错误。
确保导入语句的大小写与文件夹名称匹配后,我的提供商问题就解决了。希望这会让一些人头疼。
没有找到添加多个提供值的明确解释,我想在这里分享以供参考。
await showMobileModals(
isDismissible: false,
context: context,
child: MultiProvider(
providers: [
Provider.value(
value: provided_one,
),
Provider.value(
value: provided_two,
),
Provider.value(
value: provided_three,
),
],
child: Container(),
),
);