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 FooCubitWrapper 和 DialogWidget 是需要一些 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。
我是用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 FooCubitWrapper 和 DialogWidget 是需要一些 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。