Faced a problem when adding Bloc. I use Counter which is in Dialog
and do everything through Block but for some reason I got this error (see below). I did the same before and there was no error. I do not fully understand what the error is connected with and how to solve it correctly. I have a HomePage
class in which I declare Bloc
and in which the HomeBody
class is nested, and in this class there is a button for opening Dialog
(FilterDialog
) and in this Dialog
I have a Counter
that I did through Bloc
. I will be grateful for help.
home page
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(),
),
);
}
}
home body
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'),
),
),
),
);
}
FilterDialog
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'),
]
price counter
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,
),
],
)
],
);
}
}
counter state
class CounterState {
final double countValue;
const CounterState({required this.countValue});
}
counter cubit
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
CodePudding user response:
Unfortunately, your FilterDialog cannot find the CounterCubit provider, since showDialog is a bit tricky about it, so you have to re-supply your CounterCubit to FilterDialog in this way:
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'),
),
),
),
);
}
With BlocProvider.value you do not create a Bloc, but only assign to its child the bloc that you have already created in HomePage.
That should work, but if for some reason you are going to use this CounterCubit in another page and you don't want to use BlocProvider.value again, I strongly suggest that you make it global, in other words that you provide the CounterCubit in all your application in this way :
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(),
),
);
}
}
With this, now every application will be able to get the context of your CounterCubit.
With both codes, one with the BlocProvider.value or without it and using it global, it works.