如何操作-带有持久子画面的Flutter Drawer

时间:2018-10-24 01:13:47

标签: navigation flutter drawer

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

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

所以,问题是:如何在Flutter中实现类似的目标?我慢慢地了解“小部件树”,但是,由于“屏幕”(实际上只是小部件)被“推入”树中,当前显示的屏幕会发生什么?我了解导航堆栈,但是上一个屏幕,其小部件和其数据(内存)如何处理?他们会从树上“擦除”吗?从以前看到的问题来看,我认为答案是“是”。一旦“推开”屏幕被“重新推到”,它将重新开始其整个生命,这意味着它必须重新获取数据,滚动,过滤,渲染等。

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

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

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

(一旦进入详细信息页面,您只能单击“后退”按钮,抽屉仅在列表和其他顶层页面上可用)。

列表本身可以排序,分页,可以过滤和快速搜索。每个列表将其状态保存到基于“继承的窗口小部件”模式的会话中。我基于此帖子建立了Session课程:

Flutter: How to correctly use an Inherited Widget?

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

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

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

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

这里是我的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(),
      ),
    );
  }
}

这意味着我可以从应用程序中的任何位置访问该会话并将其存储在其中。然后在应用程序中的任何地方使用它的方式就像:

ListPagePreferences savedPrefs = Session.of(context).myListPrefs;

还有其他保存状态的方法,但这对于我们的需求而言非常简单明了。