您使用的上下文来自 BlocProvider 上方的小部件。我用对话框
The context you are using comes from the widget above the BlocProvider. I use Dialog
添加 Bloc 时遇到问题。我使用 Dialog
中的 Counter 并通过 Block 执行所有操作,但由于某种原因我收到此错误(见下文)。我之前也是这样做的,没有报错。我不完全了解错误与什么有关以及如何正确解决。我有一个 HomePage
class,我在其中声明了 Bloc
,其中嵌套了 HomeBody
class,在这个 class 中有一个打开 Dialog
(FilterDialog
) 的按钮,在这个 Dialog
中,我有一个 Counter
是我通过 Bloc
完成的。我将不胜感激。
主页
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider<CounterCubit>(
create: (context) => CounterCubit(),
child: Scaffold(
extendBodyBehindAppBar: true,
appBar: LogoAppBar(
buttonIcon: SvgPicture.asset(constants.Assets.burgerMenu)),
body: const HomeBody(),
),
);
}
}
首页正文
class HomeBody extends StatelessWidget {
const HomeBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Container(
width: size.width,
height: size.height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/background/main_background.png'),
fit: BoxFit.cover,
),
),
child: _child(context, size),
);
}
Widget _child(context, Size size) => Padding(
padding: const EdgeInsets.only(top: 121, right: 24),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
return const FilterDialog();
},
);
},
child: Container(
height: 40,
width: 50,
decoration: const BoxDecoration(
color: Colors.amber,
),
alignment: Alignment.center,
child: const Text('Dialog'),
),
),
),
);
}
过滤对话框
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Dialog(
insetPadding: const EdgeInsets.only(top: 100, left: 24, right: 24),
backgroundColor: Colors.transparent,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(24))),
child: Container(
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
color: constants.Colors.greyDark,
borderRadius: BorderRadius.all(Radius.circular(24)),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(21, 38, 21, 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PriceCounter(title: 'From'),
]
价格计数器
class PriceCounter extends StatelessWidget {
final String title;
const PriceCounter({Key? key, required this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
final CounterCubit cubit = BlocProvider.of<CounterCubit>(context);
return Column(
children: [
BlocBuilder<CounterCubit, CounterState>(
builder: (context, state) => InputField(
price: state.countValue.toString(),
textStyle: constants.Styles.normalBookTextStyleWhite),
),
Row(
children: [
IconButton(
onPressed: () => cubit.increment(),
icon: SvgPicture.asset(constants.Assets.plus),
constraints: const BoxConstraints(),
padding: EdgeInsets.zero,
),
Text('Test', style: constants.Styles.smallLtStdTextStyleWhite),
IconButton(
onPressed: () => cubit.decrement(),
icon: SvgPicture.asset(constants.Assets.minus),
constraints: const BoxConstraints(),
padding: EdgeInsets.zero,
),
],
)
],
);
}
}
计数器状态
class CounterState {
final double countValue;
const CounterState({required this.countValue});
}
反肘
class CounterCubit extends Cubit<CounterState> {
CounterCubit() : super(const CounterState(countValue: 0.13));
void increment() => emit(CounterState(countValue: state.countValue + 0.1));
void decrement() => emit(CounterState(countValue: state.countValue - 0.1));
}
The following assertion was thrown building PriceCounter(dirty):
BlocProvider.of() called with a context that does not contain a CounterCubit.
No ancestor could be found starting from the context that was passed to BlocProvider.of<CounterCubit>().
This can happen if the context you used comes from a widget above the BlocProvider.
The context used was: PriceCounter(dirty)
The relevant error-causing widget was PriceCounter
lib\…\widgets\filter_dialog.dart:233 When the exception was thrown,
this was the stack
不幸的是,您的 FilterDialog 找不到 CounterCubit 提供程序,因为 showDialog 有点这很棘手,所以你必须 re-supply 你的 CounterCubit 到 FilterDialog 这样:
Widget _child(context, Size size) => Padding(
padding: const EdgeInsets.only(top: 121, right: 24),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
return BlocProvider.value( // in this way
value: CounterCubit(),
child: FilterDialog(),
);
},
);
},
child: Container(
height: 40,
width: 50,
decoration: const BoxDecoration(
color: Colors.amber,
),
alignment: Alignment.center,
child: const Text('Dialog'),
),
),
),
);
}
使用 BlocProvider.value 您不会创建一个 Bloc,而只会将您已经在 HomePage.
这应该可行,但是如果出于某种原因您打算在另一个页面中使用此 CounterCubit 而您不想使用 BlocProvider.value 再次,我强烈建议您将其设为全局,换句话说,您以这种方式在所有应用程序中提供 CounterCubit :
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CounterCubit(), // here
child: MaterialApp(
title: 'Material App',
debugShowCheckedModeBanner: false,
home: const HomePage(),
),
);
}
}
有了这个,现在每个应用程序都可以获取您的 CounterCubit 的上下文。
使用这两种代码,一个带有 BlocProvider.value 或不带它并在全球范围内使用它,都有效。
添加 Bloc 时遇到问题。我使用 Dialog
中的 Counter 并通过 Block 执行所有操作,但由于某种原因我收到此错误(见下文)。我之前也是这样做的,没有报错。我不完全了解错误与什么有关以及如何正确解决。我有一个 HomePage
class,我在其中声明了 Bloc
,其中嵌套了 HomeBody
class,在这个 class 中有一个打开 Dialog
(FilterDialog
) 的按钮,在这个 Dialog
中,我有一个 Counter
是我通过 Bloc
完成的。我将不胜感激。
主页
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider<CounterCubit>(
create: (context) => CounterCubit(),
child: Scaffold(
extendBodyBehindAppBar: true,
appBar: LogoAppBar(
buttonIcon: SvgPicture.asset(constants.Assets.burgerMenu)),
body: const HomeBody(),
),
);
}
}
首页正文
class HomeBody extends StatelessWidget {
const HomeBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
return Container(
width: size.width,
height: size.height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/background/main_background.png'),
fit: BoxFit.cover,
),
),
child: _child(context, size),
);
}
Widget _child(context, Size size) => Padding(
padding: const EdgeInsets.only(top: 121, right: 24),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
return const FilterDialog();
},
);
},
child: Container(
height: 40,
width: 50,
decoration: const BoxDecoration(
color: Colors.amber,
),
alignment: Alignment.center,
child: const Text('Dialog'),
),
),
),
);
}
过滤对话框
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Dialog(
insetPadding: const EdgeInsets.only(top: 100, left: 24, right: 24),
backgroundColor: Colors.transparent,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(24))),
child: Container(
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
color: constants.Colors.greyDark,
borderRadius: BorderRadius.all(Radius.circular(24)),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(21, 38, 21, 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
PriceCounter(title: 'From'),
]
价格计数器
class PriceCounter extends StatelessWidget {
final String title;
const PriceCounter({Key? key, required this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
final CounterCubit cubit = BlocProvider.of<CounterCubit>(context);
return Column(
children: [
BlocBuilder<CounterCubit, CounterState>(
builder: (context, state) => InputField(
price: state.countValue.toString(),
textStyle: constants.Styles.normalBookTextStyleWhite),
),
Row(
children: [
IconButton(
onPressed: () => cubit.increment(),
icon: SvgPicture.asset(constants.Assets.plus),
constraints: const BoxConstraints(),
padding: EdgeInsets.zero,
),
Text('Test', style: constants.Styles.smallLtStdTextStyleWhite),
IconButton(
onPressed: () => cubit.decrement(),
icon: SvgPicture.asset(constants.Assets.minus),
constraints: const BoxConstraints(),
padding: EdgeInsets.zero,
),
],
)
],
);
}
}
计数器状态
class CounterState {
final double countValue;
const CounterState({required this.countValue});
}
反肘
class CounterCubit extends Cubit<CounterState> {
CounterCubit() : super(const CounterState(countValue: 0.13));
void increment() => emit(CounterState(countValue: state.countValue + 0.1));
void decrement() => emit(CounterState(countValue: state.countValue - 0.1));
}
The following assertion was thrown building PriceCounter(dirty): BlocProvider.of() called with a context that does not contain a CounterCubit.
No ancestor could be found starting from the context that was passed to BlocProvider.of<CounterCubit>(). This can happen if the context you used comes from a widget above the BlocProvider. The context used was: PriceCounter(dirty)
The relevant error-causing widget was PriceCounter lib\…\widgets\filter_dialog.dart:233 When the exception was thrown, this was the stack
不幸的是,您的 FilterDialog 找不到 CounterCubit 提供程序,因为 showDialog 有点这很棘手,所以你必须 re-supply 你的 CounterCubit 到 FilterDialog 这样:
Widget _child(context, Size size) => Padding(
padding: const EdgeInsets.only(top: 121, right: 24),
child: Align(
alignment: Alignment.topRight,
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
return BlocProvider.value( // in this way
value: CounterCubit(),
child: FilterDialog(),
);
},
);
},
child: Container(
height: 40,
width: 50,
decoration: const BoxDecoration(
color: Colors.amber,
),
alignment: Alignment.center,
child: const Text('Dialog'),
),
),
),
);
}
使用 BlocProvider.value 您不会创建一个 Bloc,而只会将您已经在 HomePage.
这应该可行,但是如果出于某种原因您打算在另一个页面中使用此 CounterCubit 而您不想使用 BlocProvider.value 再次,我强烈建议您将其设为全局,换句话说,您以这种方式在所有应用程序中提供 CounterCubit :
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CounterCubit(), // here
child: MaterialApp(
title: 'Material App',
debugShowCheckedModeBanner: false,
home: const HomePage(),
),
);
}
}
有了这个,现在每个应用程序都可以获取您的 CounterCubit 的上下文。
使用这两种代码,一个带有 BlocProvider.value 或不带它并在全球范围内使用它,都有效。