我是 Flutter 的新手,我正在尝试找出如何实现我在网络编程方面所做的事情,即拥有一个具有多个“区域”的应用程序,这些“区域”可以同时处于“实时/当前”状态.想象一个应用程序有 4 个“区域”。 4 个区域中的每一个都有一个“开始”屏幕,通常是该区域中的项目列表。用户可以使用该区域的辅助“子”屏幕查看列表项的详细信息,或创建新的列表项。 4 个“区域”屏幕中的每一个还包括一个抽屉,用于将“当前 View ”切换到特定区域。这个概念是:用户可以转到一个区域、滚动列表、过滤列表等。然后他们可以要求抽屉转到另一个区域,在那里他们可以在该屏幕上执行类似的操作。然后他们应该能够使用抽屉 [重新] 转到第一个区域,或转到他们想要的任何其他区域,并且当他们到达那里时,该屏幕的“内容”(数据)应该与它完全相同在他们离开那个屏幕之前。请注意,如果他们“深入”列表项或创建新项,则他们无法访问“区域抽屉”,只能“返回”到该区域的列表屏幕。
在网络编程中,每个“区域”都是一个 div,并且都“存在”在一个页面上。抽屉元素会根据用户的需要简单地隐藏和显示每个 div,并且每个 div 在隐藏时都保持“不变”。
所以,问题是:如何在 Flutter 中实现这样的功能?我正在慢慢理解“小部件树”的事情,但是,随着“屏幕”(实际上只是小部件)被“推”到树中,当前显示的屏幕会发生什么情况?我了解导航堆栈,但是前一个屏幕、它的小部件和它的数据(内存)会发生什么?它们会从树上“消失”吗?从我之前看到的问题来看,我认为答案是"is"。一旦“推离”屏幕被“重新插入”,它就会重新开始它的生活,这意味着它必须重新获取数据、滚动它、过滤它、渲染它等等。
我想我想知道的是,该应用程序能否同时在内存中、树中有多个“区域”(屏幕),但一次只能“看到”一个,并且每个区域都有自己的自己的“ child 屏幕导航”。我确信我正在以“错误”的方式处理问题,但每个工具包/编程系统似乎都以不同的方式处理这个问题,我只是不确定如何使用 Flutter 来解决这个问题。我知道我可以将每个区域的“开始”页面的所有“数据”保留在内存中(在应用程序级别),因此可以从该数据重建每个区域(无需转到数据库)。我还听过一些人讨论“线性导航”(相对于分层导航?),但对此知之甚少。
感谢您的帮助。
最佳答案
这与我们几个月前遇到的问题非常相似。我们有一个抽屉,上面有四个不同 list 的链接。这些列表彼此完全独立,并且是它们自己的页面。您还可以点击列表中的其中一项,然后进入详细信息页面。
(一旦您进入详细信息页面,您只能点击后退按钮,抽屉仅在列表和其他顶级页面上可用)。
列表本身是可排序、分页、过滤和快速搜索的。每个列表将其状态保存到基于继承的小部件模式的 session 中。我的 Session 类基于这篇文章:
Flutter: How to correctly use an Inherited Widget?
如果您转到列表 A,对一列进行排序,使用抽屉移动到列表 B,然后按回键返回列表 A,该列表将显示为您离开时的状态。
如果您要转到列表 A,对一列进行排序,使用抽屉移动到列表 B,然后再次使用抽屉转到列表 A,列表将显示为您离开时的相同状态。
这两种情况的区别在于导航堆栈的外观。在第一种情况下,堆栈只是列表 A。在第二种情况下,堆栈是列表 A、列表 B、列表 A。
如果您采用第二种情况,对列表 A 进行更改,然后弹出堆栈两次(点击后退按钮),堆栈底部的列表 A 实际上看起来就像您更改的更高层的列表 A在堆栈上。
下面是支持保存其中一个列表状态的 Session 类的部分 View 。请注意,这是有意称为 Session 的,当应用程序关闭时,应用程序会忘记此状态。不过,保存到共享存储会相对容易。
class Session extends StatefulWidget {
final Widget child;
Session({this.child});
@override
SessionState createState() => SessionState();
static SessionState of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(_Session) as _Session).data;
}
}
class SessionState extends State<Session> {
ListPagePreferences _myListPrefs = ListPagePreferences();
//called when the user logs out, for example
void clear() {
setState(() {
_myListPrefs = ListPagePreferences();
});
}
ListPagePreferences get myListPrefs => _myListPrefs;
void updatePrefs({
ListPagePreferences prefs,
rowsPerPage,
startIndex,
sortColumnIndex,
sortAscending,
searchValue,
filter,
}) {
setState(() {
prefs.updatePrefs(
rowsPerPage: rowsPerPage,
startIndex: startIndex,
sortColumnIndex: sortColumnIndex,
sortAscending: sortAscending,
searchValue: searchValue,
filter: filter,
);
});
}
@override
Widget build(BuildContext context) {
return _Session(
data: this,
child: widget.child,
);
}
}
class _Session extends InheritedWidget {
final SessionState data;
_Session({Key key, this.data, Widget child}) : super(key: key, child: child);
@override
bool updateShouldNotify(_Session old) => true;
}
然后我的应用程序被这个继承的小部件包裹:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return Session(
child: MaterialApp(
title: "My App",
home: WelcomePage(),
),
);
}
}
这意味着我可以从应用程序的任何位置访问 session 并将内容存储在其中。它在应用程序中任何地方的使用方式如下:
ListPagePreferences savedPrefs = Session.of(context).myListPrefs;
还有其他方法可以保存状态,但这对我们的需求来说非常简单易行。
关于navigation - 如何 - 带有持久子屏幕的 Flutter Drawer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52959801/