您使用的上下文来自 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 你的 CounterCubitFilterDialog 这样:

  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 或不带它并在全球范围内使用它,都有效。