在执行 Widget 状态构建时导航
Navigate while Widget state build is being executed
我正在构建一个简单的 Flutter 应用程序。它的启动屏幕确定用户是否登录,并根据该情况重定向到登录或之后的 main/home 屏幕。
我的启动屏幕是 StatefulWidget
,其状态如下所示。它使用扩展 ChangeNotifier
的 ViewModel class(它的代码不相关,所以我没有包含它)。
class _LaunchPageState extends State<LaunchPage> {
LaunchViewModel _viewModel = LaunchViewModel();
@override
void initState() {
super.initState();
_viewModel.checkSessionStatus();
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<LaunchViewModel>(
builder: (_) => _viewModel,
child: Scaffold(
body: Consumer<LaunchViewModel>(
builder: (context, viewModel, _) {
if (viewModel.state is LaunchInitial) {
return CircularProgressIndicator();
}
if (viewModel.state is LaunchLoginPage) {
Navigator.pushNamed(context, "login");
}
if (viewModel.state is LaunchMainPage) {
Navigator.pushNamed(context, "main");
}
return Container();
},
),
),
);
}
}
ViewModel 发出 3 种状态之一:
- LaunchInitial:默认状态。
- LaunchLoginPage:表示应显示登录页面。
- LaunchMainPage:表示应显示主页。
LaunchInitial 状态处理良好,屏幕上显示进度条。但其他 2 个状态导致应用程序崩溃。抛出以下错误:
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets
似乎是在执行消费者的 build
方法时尝试重定向到另一个屏幕导致了这个问题。正确的做法是什么?
谢谢!
您不能在小部件树中直接调用 Navigator
。如果您有 event-state
生成器,那么最好更改您正在渲染的小部件树:
builder: (context, viewModel, _) {
if (viewModel.state is LaunchInitial) {
return CircularProgressIndicator();
}
if (viewModel.state is LaunchLoginPage) {
return LoginPage();
}
if (viewModel.state is LaunchMainPage) {
return MainPage();
}
return Container();
},
你必须 return Widget
与 build
方法中的每个 child。
或者,您可以使用 Navigation
:
@override
void didChangeDependencies() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (viewModel.state is LaunchLoginPage) {
Navigator.pushNamed(context, "login");
}
if (viewModel.state is LaunchMainPage) {
Navigator.pushNamed(context, "main");
}
});
super.didChangeDependencies();
}
addPostFrameCallback
方法将在 build
方法完成后立即调用,您可以在其中导航。
确保您的 provider
没有 lifecycle
问题。
我正在构建一个简单的 Flutter 应用程序。它的启动屏幕确定用户是否登录,并根据该情况重定向到登录或之后的 main/home 屏幕。
我的启动屏幕是 StatefulWidget
,其状态如下所示。它使用扩展 ChangeNotifier
的 ViewModel class(它的代码不相关,所以我没有包含它)。
class _LaunchPageState extends State<LaunchPage> {
LaunchViewModel _viewModel = LaunchViewModel();
@override
void initState() {
super.initState();
_viewModel.checkSessionStatus();
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<LaunchViewModel>(
builder: (_) => _viewModel,
child: Scaffold(
body: Consumer<LaunchViewModel>(
builder: (context, viewModel, _) {
if (viewModel.state is LaunchInitial) {
return CircularProgressIndicator();
}
if (viewModel.state is LaunchLoginPage) {
Navigator.pushNamed(context, "login");
}
if (viewModel.state is LaunchMainPage) {
Navigator.pushNamed(context, "main");
}
return Container();
},
),
),
);
}
}
ViewModel 发出 3 种状态之一:
- LaunchInitial:默认状态。
- LaunchLoginPage:表示应显示登录页面。
- LaunchMainPage:表示应显示主页。
LaunchInitial 状态处理良好,屏幕上显示进度条。但其他 2 个状态导致应用程序崩溃。抛出以下错误:
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets
似乎是在执行消费者的 build
方法时尝试重定向到另一个屏幕导致了这个问题。正确的做法是什么?
谢谢!
您不能在小部件树中直接调用 Navigator
。如果您有 event-state
生成器,那么最好更改您正在渲染的小部件树:
builder: (context, viewModel, _) {
if (viewModel.state is LaunchInitial) {
return CircularProgressIndicator();
}
if (viewModel.state is LaunchLoginPage) {
return LoginPage();
}
if (viewModel.state is LaunchMainPage) {
return MainPage();
}
return Container();
},
你必须 return Widget
与 build
方法中的每个 child。
或者,您可以使用 Navigation
:
@override
void didChangeDependencies() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (viewModel.state is LaunchLoginPage) {
Navigator.pushNamed(context, "login");
}
if (viewModel.state is LaunchMainPage) {
Navigator.pushNamed(context, "main");
}
});
super.didChangeDependencies();
}
addPostFrameCallback
方法将在 build
方法完成后立即调用,您可以在其中导航。
确保您的 provider
没有 lifecycle
问题。