How To - 带有持久子屏幕的 Flutter Drawer

Posted

技术标签:

【中文标题】How To - 带有持久子屏幕的 Flutter Drawer【英文标题】:How To - Flutter Drawer with persistent child screens 【发布时间】:2019-03-28 07:49:53 【问题描述】:

我是 Flutter 的新手,正在尝试找出如何实现我在 Web 编程方面所做的事情,即拥有一个具有多个“区域”的应用程序,这些“区域”都可以同时处于“实时/当前”状态.想象一个有 4 个“区域”的应用程序。 4 个区域中的每一个都有一个“开始”屏幕,通常是该区域内的项目列表。用户可以使用该区域的辅助“子”屏幕查看列表项的详细信息,或创建新的列表项。 4 个“区域”屏幕中的每一个还包括一个抽屉,用于将“当前视图”切换到特定区域。这个概念是:用户可以去一个区域,滚动列表,过滤列表等。然后他们可以要求抽屉去一个不同的区域,在那里他们可以在那个屏幕上执行类似的操作。然后他们应该能够使用抽屉 [re] 去第一个区域,或者去他们想要的任何其他区域,并且,当他们到达那里时,该屏幕的“内容”(数据)应该与它完全相同在他们离开那个屏幕之前。请注意,如果他们“深入”列表项或创建新项,他们将无法访问“区域抽屉”,只能“返回”到该区域的列表屏幕。

在网络编程中,每个“区域”都是一个 div,并且都“存在”在一个页面上。抽屉元素会根据用户的需要简单地隐藏和显示每个 div,每个 div 在隐藏时都保持“未触及”。

所以,问题是:如何在 Flutter 中实现这样的功能?我正在慢慢理解“小部件树”的事情,但是,当“屏幕”(实际上只是小部件)被“推”到树中时,当前显示的屏幕会发生什么?我了解导航堆栈,但是前一个屏幕、它的小部件和它的数据(内存)会发生什么?他们会从树上“抹去”吗?从我以前看到的问题来看,我认为答案是“是”。一旦“被推开”的屏幕被“重新推”到,它就会重新开始它的生命,这意味着它必须重新获取数据、滚动、过滤、渲染等等。

我想我想知道的是,该应用程序是否可以同时在内存中、树中具有多个“区域”(屏幕),但一次只能“看到”一个,并且每个区域都有其自己的“子屏幕导航”。我确信我以“错误”的方式处理事情,但每个工具包/编程系统似乎都以不同的方式处理这个问题,我只是不确定如何使用 Flutter 来解决这个问题。我知道我可以将每个区域的“开始”页面的所有“数据”保存在内存中(在应用程序级别),因此可以从该数据重新构建每个区域(无需进入数据库)。我还听一些人讨论过“线性导航”(相对于分层?),但对此知之甚少。

感谢您的帮助。

【问题讨论】:

【参考方案1】:

这与我们几个月前遇到的问题非常相似。我们有一个抽屉,里面有四个不同列表的链接。这些列表彼此完全独立,并且是它们自己的页面。您还可以点击列表中的其中一项并进入详细信息页面。

(一旦您进入详细信息页面,您只能点击返回按钮,抽屉仅在列表和其他***页面上可用)。

列表本身是可排序的、分页的、可以过滤的和快速搜索的。每个列表都将其状态保存到基于 Inherited Widget 模式的会话中。我的 Session 课程基于这篇文章:

Flutter: How to correctly use an Inherited Widget?

如果您要转到列表 A,对列进行排序,使用抽屉移动到列表 B,然后回击返回列表 A,则列表将显示为与您离开时相同的状态。

如果您要转到列表 A,对列进行排序,使用抽屉移动到列表 B,然后再次使用抽屉转到列表 A,列表将显示为与您离开时相同的状态。

这两种情况之间的区别在于导航堆栈的外观。在第一种情况下,堆栈只是列表 A。在第二种情况下,堆栈是列表 A、列表 B、列表 A。

如果您要采用第二种情况,对 List A 进行更改,然后将堆栈弹出两次(按返回按​​钮),堆栈底部的 List A 实际上看起来像您在更高位置更改的 List A在堆栈上。

下面是我的 Session 类的部分内容,它支持保存其中一个列表的状态。请注意,这被故意称为 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;

还有其他方法可以保存状态,但这对于我们的需要来说非常简单明了。

【讨论】:

以上是关于How To - 带有持久子屏幕的 Flutter Drawer的主要内容,如果未能解决你的问题,请参考以下文章

Flutter How to Scaffold layout size(错误)

Flutter: How to fix ITMS-90809: Deprecated API Usage - Apple 将停止接受使用 UIWebView API 的应用程序提交

如何让我们的列表持久化,同时在 Flutter 应用程序中导航到不同的屏幕?

Flutter - 如何让带有孩子的容器占据整个屏幕

在 Flutter 中保持响应的同时制作持久的背景图像

如何在 Flutter 的同一屏幕中管理两个带有数据的 ListView