Flutter - 使用 showDialog 时无法在父树中找到 bloc

Flutter - Cant find bloc in the parent tree when using showDialog

我是用Flutter和flutter_bloc做一个小app,我用MultiBlocProvider在主主页使用我需要的多个BlocProvider,在主页下面有一个MainWidget,可以访问给定的 Bloc 很容易通过:BlocProvider.of<OldBloc>(context) MainWidget 通过以下方式调用 NewWidget 作为对话框:showDialog(context: context, builder: (context) => NewWidget()) 问题是,我无法从 NewWidget() 访问 OldBloc,所以我假设 MainWidget 在使用 showDialog 时没有将其上下文传递给 NewWidget?

HomeScreen.dart

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) => OldBloc()..add(Initialize()),
        ),
        BlocProvider(
          create: (context) => OtherBloc()..add(Initialize()),
        ),
      ],
      child: Stack(
        children: [
          MainWidget(),
          MenuWidget(),
        ],
      ),
    ));
  }
}

MainWidget.dart

import 'package:flutter/material.dart';

class MainWidget extends StatelessWidget {
  const MainWidget({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextField(onTap: () => showDialog(context: context, builder: (context) => NewWidget()));
  }
}

NewWidget.dart

import 'package:flutter/material.dart';

class NewWidget extends StatelessWidget {
  const NewWidget({Key key}) : super(key: key);

  @override
  Widget build(context) {
    return Text(BlocProvider.of<OldBloc>(context).name); // <------- THIS GIVES AN ERROR THAT IT CANT FIND A BLOC OF THE TYPE OldBloc
  }
}

您无法在 showDialog 方法中访问 BuildContext,文档:

The widget returned by the builder does not share a context with the location that showDialog is originally called from.

The context argument is used to look up the Navigator and Theme for the dialog. It is only used when the method is called.

也推荐使用StatefulBuilder或自定义StatefulWidget,这里是example

我解决了这个问题。

我使用 cubit 而不是 bloc 但这没关系。

ShowDialog 不传递父上下文。因此,您应该创建一个新的腕尺,并在新腕尺的参数中传递您的父腕尺和状态。我调用了 main cubit FooCubit,new cubit FooCubitWrapperDialogWidget 是需要一些 BLOC 逻辑的子部件显示对话框。


    var fooCubit = context.read<FooCubit>(); // your parrent cubit and state
    return BlocBuilder<FooCubit , FooState>(
        builder: (_, state) {
.
.///some logic///
.
          showDialog(
            context: context,
            builder: (_) => // here you have to create new cubit 
                BlocProvider( // because there is no access to parent cubit
                  create: (_) => FooCubitWrapper(cubit, state),
                  child: DialogWidget(),
                ),
          );

这是 FooCubitWrapper。比如我们需要父cubit的boo方法。所以我们需要在这里创建 boo 方法,在里面我们需要引用父 boo 方法并发出父状态。

class FooCubitWrapper extends Cubit<FooState> {
  FooCubit fooCubit;

  FooCubitWrapper(this.fooCubit, FooState initialState) : super(initialState);

  boo() {
    fooCubit.boo();

    emit(fooCubit.state);
  }
}

最后,在您的 DialogWidget 中,一切照常进行

    var cubit = context.read<TagsCubitWrapper>();
    return BlocBuilder<TagsCubitWrapper, TagsState>(
        builder: (context, state) {

// work with methods and fields as usual
    cubit.boo();
    if !(state.someField) {}

});

您可以简单地使用这个(由 Flex Angelov 建议):

showDialog(
  context: superContext,
  builder: (_) {
    return  BlocProvider.value(
      value: superContext.read<MyBloc>(),
      child: const MyDialogWidget(),
    );
  },
);

并确保 superContext 可以访问您的 BLoC。