Flutter:在 Drawer 中更改 body 时保留状态
Posted
技术标签:
【中文标题】Flutter:在 Drawer 中更改 body 时保留状态【英文标题】:Flutter: preserve state when changing body in Drawer 【发布时间】:2019-09-27 06:11:51 【问题描述】:我正在使用 Material 库的 Drawer
类创建一个带有导航抽屉的 Flutter 应用程序。包含Drawer
的Widget
是StatefulWidget
,Scaffold
的内容根据导航抽屉上的选定项显示。内容是WidgetOne
或WidgetTwo
,两者都保持自己的状态为StatefulWidget
s。请参阅下面的代码示例。
目前,当我从一个小部件切换到另一个小部件并返回时,之前显示的小部件的整个状态都会重新加载。这并不理想,因为这两个小部件都有来自 API 的网络调用,并且需要相应地重绘。
到目前为止我已经尝试过什么
在两个子小部件上实现AutomaticKeepAliveClientMixin
,如下所示:https://***.com/a/50074067/4009506。但是,这似乎不起作用。
按照此处的建议使用IndexedStack
:https://***.com/a/54999503/4009506。这会直接加载所有小部件,即使它们尚未显示。
代码
class DrawerWidget extends StatefulWidget
@override
State<StatefulWidget> createState() => _DrawerState();
class _DrawerState extends State<DrawerWidget>
Widget _activeWidget;
@override
void initState()
_activeWidget = FirstWidget();
super.initState();
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(title: Text("Drawer demo")),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
ListTile(
title: Text("First Widget"),
onTap: ()
setState(()
_activeWidget = FirstWidget();
);
,
),
ListTile(
title: Text("Second Widget"),
onTap: ()
setState(()
_activeWidget = SecondWidget();
);
,
),
],
),
),
body: _activeWidget);
class FirstWidget extends StatefulWidget
// [..]
class SecondWidget extends StatefulWidget
// [..]
想要的结果
WidgetOne
和 WidgetTwo
仅在初始加载时加载(在 Drawer
中选择它们之后)。如果之前已经加载过,则切换到另一个小部件并返回不应重新加载小部件。子小部件不应全部直接加载,只有在它们最初被按下时才加载。
实际结果
FirstWidget
和 SecondWidget
每次在 Drawer
中被选中时都会重新加载和重绘。
【问题讨论】:
您需要一个 PageView 或类似的东西,KeepAlive
才能工作。
【参考方案1】:
我通过使用PageView
并在所有子小部件上实现AutomaticKeepAliveClientMixin
解决了这个问题:
class DrawerWidget extends StatefulWidget
@override
State<StatefulWidget> createState() => _DrawerState();
class _DrawerState extends State<DrawerWidget>
final _pageController = PageController();
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(title: Text("Drawer demo")),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
ListTile(
title: Text("First Widget"),
onTap: ()
_pageController.jumpToPage(0);
,
),
ListTile(
title: Text("Second Widget"),
onTap: ()
_pageController.jumpToPage(1);
,
),
],
),
),
body: PageView(
controller: _pageController,
children: <Widget>[
FirstWidget(),
SecondWidget()
],
physics: NeverScrollableScrollPhysics()
));
class FirstWidget extends StatefulWidget
@override
State<StatefulWidget> createState() => _FirstWidgetState();
class _FirstWidgetState extends State<FirstWidget> with AutomaticKeepAliveClientMixin<FirstWidget>
// [..]
@override
bool get wantKeepAlive => true;
class SecondWidget extends StatefulWidget
@override
State<StatefulWidget> createState() => _SecondWidgetState();
class _SecondWidgetState extends State<SecondWidget> with AutomaticKeepAliveClientMixin<SecondWidget>
// [..]
@override
bool get wantKeepAlive => true;
现在,所有小部件仅在导航抽屉中的初始切换时加载,并且在切换回时不会重新加载。
【讨论】:
以上是关于Flutter:在 Drawer 中更改 body 时保留状态的主要内容,如果未能解决你的问题,请参考以下文章
Flutter,如何制作按钮以在 Flutter 中打开抽屉 [重复]