使用 BLoC 的 Flutter 导航:用于从 Navigator 推送路由的上下文必须是 Navigator 小部件的后代
Posted
技术标签:
【中文标题】使用 BLoC 的 Flutter 导航:用于从 Navigator 推送路由的上下文必须是 Navigator 小部件的后代【英文标题】:Flutter navigation using BLoC: The context used to push routes from the Navigator must be a descendant of a Navigator widget 【发布时间】:2019-07-12 04:01:46 【问题描述】:我正在使用 BLoC,我需要从 PageOne 导航到 PageTwo 并能够使用后退按钮返回,我不知道这是否是处理此问题的正确方法。 当函数 _navigateToPage2 被调用时,我也遇到了错误。
用于从 Navigator 推送或弹出路由的上下文必须是作为 Navigator 小部件后代的小部件的上下文。
class SimpleBlocDelegate extends BlocDelegate
@override
void onTransition(Transition transition)
print(transition);
@override
void onError(Object error, StackTrace stacktrace)
print(error);
void main()
BlocSupervisor().delegate = SimpleBlocDelegate();
runApp(MyApp(userRepository: UserRepository(GuriApi())));
class MyApp extends StatefulWidget
final UserRepository userRepository;
MyApp(Key key, @required this.userRepository) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
class _MyAppState extends State<MyApp>
AuthenticationBloc _authenticationBloc;
UserRepository get _userRepository => widget.userRepository;
@override
void initState()
_authenticationBloc = AuthenticationBloc(userRepository: _userRepository);
_authenticationBloc.dispatch(AppStarted());
super.initState();
@override
void dispose()
_authenticationBloc.dispose();
super.dispose();
@override
Widget build(BuildContext context)
return BlocProvider<AuthenticationBloc>(
bloc: _authenticationBloc,
child: MaterialApp(
theme: new ThemeData(
fontFamily: 'Monserrat',
primaryColor: Colors.lightBlue[50],
accentColor: Colors.white),
home: BlocBuilder<AuthenticationEvent, AuthenticationState>(
bloc: _authenticationBloc,
builder: (BuildContext context, AuthenticationState state)
if (state is AuthenticationUninitialized)
return SplashPage();
if (state is AuthenticationAuthenticated)
return Home(userRepository: _userRepository);
if (state is AuthenticationUnauthenticated)
return LoginPage(userRepository: _userRepository);
if (state is AuthenticationLoading)
return LoadingIndicator();
if (state is PageOneSelected)
return PageOne();
if (state is PageTwoSelected)
_navigateToPage2();
,
),
),
);
_navigateToPage2()
Navigator.of(context).push<bool>(
MaterialPageRoute(
builder: (BuildContext context) =>
PageTwo(userRepository: _userRepository)));
【问题讨论】:
【参考方案1】:有必要在你的小部件中做这样的事情:
if (state is PageTwoSelected)
WidgetsBinding.instance.addPostFrameCallback((_)
Navigator.push(context,
MaterialPageRoute(builder: (context) =>
PageTwo(userRepository: _userRepository))
);
);
这是必要的,因为如果在小部件仍在构建(处于脏状态)时发生导航,Flutter 将抛出异常。
通过将其嵌套在 addPostFrameCallback 的回调中,您基本上是在说当小部件完成构建时,然后执行导航代码。
你可以阅读更多关于它的信息here,在 cmets 中有解释。
【讨论】:
【参考方案2】:我认为最好通过在initState中订阅bloc状态变化来处理导航:
@override
void initState()
super.initState();
bloc.state.listen((state)
if (state is PageOneSelected)
_navigateToPage2();
else if (state is PageTwoSelected)
_navigateToPage2();
);
在构建方法中显示一些其他小部件。您的代码中发生错误,因为 blocBuilder 必须返回 Widget 但在 PageTwoSelected 状态的情况下您什么也不返回。
【讨论】:
您先生刚刚救了我的命。我已经在整个互联网上搜索了答案。感谢您让这个社区变得更美好以上是关于使用 BLoC 的 Flutter 导航:用于从 Navigator 推送路由的上下文必须是 Navigator 小部件的后代的主要内容,如果未能解决你的问题,请参考以下文章
Bloc 模式是不是适合在 Flutter 应用中管理导航?
导航到不同路线后,Flutter 找不到正确的 Provider<Bloc>
Flutter BLoC 模式 - 如何在流事件后导航到另一个屏幕?