将 BlocListener 与 Navigator PushNamed 一起使用会导致歧义
Using BlocListener with Navigator PushNamed is causing ambiguity
我在使用 bloc 侦听器进行导航时遇到问题
我有五个导航屏幕,我在每个文件中都使用 BlocConsumer。我正在 flutter inspector 中寻找粒度视图。我正在使用 blocListener 进行导航。当我 pushNamed 第一个屏幕一切正常,我导航到第二个屏幕(第一个屏幕被添加到导航堆栈)。现在我在第二个屏幕,当我按下移动到第三个屏幕两个第二个屏幕然后添加第三个屏幕时,堆栈应该是这样的(第一个屏幕,第二个屏幕,第三个屏幕) 但不幸的是,它就像 (第 1 个屏幕,第 2 个屏幕,第 2 个屏幕,第 3 个屏幕)。 现在,当我在第 3 个屏幕上并想添加第 4 个屏幕时,堆栈是堆栈,但添加了第 2 个屏幕然后将第 3 个屏幕添加两次,然后添加第 4 个屏幕。堆栈应该是这样的(第一屏,第二屏,第三屏,第四屏)但不幸的是它就像(第一屏,第二屏,第二屏,第三屏屏幕,第二屏幕,第三屏幕,第三屏幕,第四屏幕)。因此,导航堆栈中有 4 个屏幕,而不是 8 个屏幕。
这是我在所有文件中使用的模式。
这是我创建 bloc 实例并关闭它的地方。
class MyAppRoutes {
FieldsBloc _fieldsBloc = FieldsBloc();
Route onGenerateRoute(RouteSettings routeSettings) {
try {
switch (routeSettings.name) {
case LandingPage.routeName:
return MaterialPageRoute(builder: (_) => LandingPage());
case CategoryPage.routeName:
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _fieldsBloc,
child: CategoryPage(),
));
case ExpertisePage.routeName:
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _fieldsBloc,
child: ExpertisePage(),
));
case ExpertiseLevelPage.routeName:
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _fieldsBloc,
child: ExpertiseLevelPage(),
));
case EducationPage.routeName:
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _fieldsBloc,
child: EducationPage(),
));
default:
return null;
}
} catch (e) {
print(e);
}
}
void dispose() async {
_fieldsBloc.close();
}
}
这是我在每个文件中使用的小部件。
BlocConsumer<FieldsBloc, FieldsState>(builder: (context, state) {
if (state is FieldsInitial) {
return Container();
} else if (state is FieldLoadingState) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: getCircularProgress(context),
);
} else if (state is FieldSuccessfulState) {
return Container();
} else if (state is FieldUnsuccessfulState) {
return Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error,
color: Colors.red,
),
SizedBox(
width: 5.0,
),
Expanded(
child: TextStyleRes.textStyleFont1(
textColor: Colors.red,
text: state.message,
fontSize: 12,
fontWeight: FontWeight.w700)),
],
));
}
return Container();
}, listener: (context, state) {
if (state is FieldSuccessfulState)
return SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pushNamed(ExpertisePage.routeName);
});
}),
这是正在触发的 Bloc 事件。
abstract class FieldsEvent {}
class NextButtonEventScreen3 extends FieldsEvent {
List<String> categories;
NextButtonEventScreen3(this.categories);
}
class NextButtonEventScreen4 extends FieldsEvent {
List skills;
NextButtonEventScreen4(this.skills);
}
class NextButtonEventScreen5 extends FieldsEvent {
String expert;
NextButtonEventScreen5(this.expert);
}
这就是集团。
if (event is NextButtonEventScreen3) {
if (event.categories.isNotEmpty) {
yield FieldLoadingState();
categories = event.categories;
yield FieldSuccessfulState();
} else
throw ('Please choose at least 1 category');
}
//=====================SignUpScreen4===========================
else if (event is NextButtonEventScreen4) {
if (event.skills.isNotEmpty) {
yield FieldLoadingState();
skills = event.skills;
yield FieldSuccessfulState(_updateModel());
} else
throw ('Please provide at least 1 skill');
}
//=====================SignUpScreen5===========================
else if (event is NextButtonEventScreen5) {
expert = event.expert;
yield FieldSuccessfulState();
}
这些是集团中的州
abstract class FieldsState {
String message;
}
class FieldsInitial extends FieldsState {}
class FieldLoadingState extends FieldsState {}
class FieldSuccessfulState extends FieldsState {
var data;
FieldSuccessfulState([this.data]);
}
class FieldUnsuccessfulState extends FieldsState {
String message;
FieldUnsuccessfulState({this.message});
}
之前导航栈上的页面还在,监听bloc事件。当状态在第二个屏幕上变为 FieldsSuccessfulState
时,两个听众都会看到这一点并尝试导航到下一个屏幕。
为了确保只有当前屏幕会响应FieldsSuccessfulState
,我能想到的有两个方案:
将 FieldsSuccessfulState
分成多个结果(不同的 类 或添加的字段)并使每个屏幕仅对自己的成功状态做出反应。
在导航到下一个屏幕之前检查 ModalRoute.of(context).isCurrent
。这可以在侦听器本身或 listenWhen
参数中完成。
我在使用 bloc 侦听器进行导航时遇到问题
我有五个导航屏幕,我在每个文件中都使用 BlocConsumer。我正在 flutter inspector 中寻找粒度视图。我正在使用 blocListener 进行导航。当我 pushNamed 第一个屏幕一切正常,我导航到第二个屏幕(第一个屏幕被添加到导航堆栈)。现在我在第二个屏幕,当我按下移动到第三个屏幕两个第二个屏幕然后添加第三个屏幕时,堆栈应该是这样的(第一个屏幕,第二个屏幕,第三个屏幕) 但不幸的是,它就像 (第 1 个屏幕,第 2 个屏幕,第 2 个屏幕,第 3 个屏幕)。 现在,当我在第 3 个屏幕上并想添加第 4 个屏幕时,堆栈是堆栈,但添加了第 2 个屏幕然后将第 3 个屏幕添加两次,然后添加第 4 个屏幕。堆栈应该是这样的(第一屏,第二屏,第三屏,第四屏)但不幸的是它就像(第一屏,第二屏,第二屏,第三屏屏幕,第二屏幕,第三屏幕,第三屏幕,第四屏幕)。因此,导航堆栈中有 4 个屏幕,而不是 8 个屏幕。
这是我在所有文件中使用的模式。
这是我创建 bloc 实例并关闭它的地方。
class MyAppRoutes {
FieldsBloc _fieldsBloc = FieldsBloc();
Route onGenerateRoute(RouteSettings routeSettings) {
try {
switch (routeSettings.name) {
case LandingPage.routeName:
return MaterialPageRoute(builder: (_) => LandingPage());
case CategoryPage.routeName:
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _fieldsBloc,
child: CategoryPage(),
));
case ExpertisePage.routeName:
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _fieldsBloc,
child: ExpertisePage(),
));
case ExpertiseLevelPage.routeName:
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _fieldsBloc,
child: ExpertiseLevelPage(),
));
case EducationPage.routeName:
return MaterialPageRoute(
builder: (context) => BlocProvider.value(
value: _fieldsBloc,
child: EducationPage(),
));
default:
return null;
}
} catch (e) {
print(e);
}
}
void dispose() async {
_fieldsBloc.close();
}
}
这是我在每个文件中使用的小部件。
BlocConsumer<FieldsBloc, FieldsState>(builder: (context, state) {
if (state is FieldsInitial) {
return Container();
} else if (state is FieldLoadingState) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: getCircularProgress(context),
);
} else if (state is FieldSuccessfulState) {
return Container();
} else if (state is FieldUnsuccessfulState) {
return Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error,
color: Colors.red,
),
SizedBox(
width: 5.0,
),
Expanded(
child: TextStyleRes.textStyleFont1(
textColor: Colors.red,
text: state.message,
fontSize: 12,
fontWeight: FontWeight.w700)),
],
));
}
return Container();
}, listener: (context, state) {
if (state is FieldSuccessfulState)
return SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pushNamed(ExpertisePage.routeName);
});
}),
这是正在触发的 Bloc 事件。
abstract class FieldsEvent {}
class NextButtonEventScreen3 extends FieldsEvent {
List<String> categories;
NextButtonEventScreen3(this.categories);
}
class NextButtonEventScreen4 extends FieldsEvent {
List skills;
NextButtonEventScreen4(this.skills);
}
class NextButtonEventScreen5 extends FieldsEvent {
String expert;
NextButtonEventScreen5(this.expert);
}
这就是集团。
if (event is NextButtonEventScreen3) {
if (event.categories.isNotEmpty) {
yield FieldLoadingState();
categories = event.categories;
yield FieldSuccessfulState();
} else
throw ('Please choose at least 1 category');
}
//=====================SignUpScreen4===========================
else if (event is NextButtonEventScreen4) {
if (event.skills.isNotEmpty) {
yield FieldLoadingState();
skills = event.skills;
yield FieldSuccessfulState(_updateModel());
} else
throw ('Please provide at least 1 skill');
}
//=====================SignUpScreen5===========================
else if (event is NextButtonEventScreen5) {
expert = event.expert;
yield FieldSuccessfulState();
}
这些是集团中的州
abstract class FieldsState {
String message;
}
class FieldsInitial extends FieldsState {}
class FieldLoadingState extends FieldsState {}
class FieldSuccessfulState extends FieldsState {
var data;
FieldSuccessfulState([this.data]);
}
class FieldUnsuccessfulState extends FieldsState {
String message;
FieldUnsuccessfulState({this.message});
}
之前导航栈上的页面还在,监听bloc事件。当状态在第二个屏幕上变为 FieldsSuccessfulState
时,两个听众都会看到这一点并尝试导航到下一个屏幕。
为了确保只有当前屏幕会响应FieldsSuccessfulState
,我能想到的有两个方案:
将
FieldsSuccessfulState
分成多个结果(不同的 类 或添加的字段)并使每个屏幕仅对自己的成功状态做出反应。在导航到下一个屏幕之前检查
ModalRoute.of(context).isCurrent
。这可以在侦听器本身或listenWhen
参数中完成。