Flutter-在应用程序的整个生命周期内保持页面静态?

时间:2019-06-01 12:46:34

标签: flutter

我创建了一个AppDrawer小部件,用于包装我的主抽屉导航并在一个地方引用它,就像这样:

class AppDrawer extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Drawer(
        child: new ListView(
          children: <Widget>[
            new ListTile(
              title: new Text("Page1"),
              trailing: new Icon(Icons.arrow_right),
              onTap: () {
                Navigator.of(context).pop();
                Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => Page1.singleInstance));
              }
            ),
            new ListTile(
              title: new Text("Page2"),
              trailing: new Icon(Icons.arrow_right),
              onTap: () {
                Navigator.of(context).pop();
                Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new Page2("Page 2")));
              }
            ),
          ]
        ),
      );
  }
}

我还创建了一个自定义AppScaffold小部件,该小部件仅返回一致的AppBar,我的自定义AppDrawer和主体:

class AppScaffold extends StatelessWidget {
  final Widget body;
  final String pageTitle;

  AppScaffold({this.body, this.pageTitle});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new AppBar(title: new Text(pageTitle), backgroundColor: jet),
      drawer: AppDrawer(), 
      body: body
    );
  }
}

我创建了两个页面:Page1和Page2。它们现在很简单,看起来像这样:

class Page1 extends StatelessWidget {
  final String pageText;

  Page1(this.pageText);

  static Page1 get singleInstance => Page1("Page1");

  Widget build(BuildContext context) {
    return AppScaffold(
      pageTitle: this.pageText,
      body: SafeArea(
        child: Stack(
          children: <Widget>[
            Center(child: SomeCustomWidget())
          ],
        )
      ),
    );
  }
}

class Page2 extends StatelessWidget {
  final String pageText;

  Page2(this.pageText);

  @override
  Widget build(BuildContext context) {
    return AppScaffold(
      pageTitle: this.pageText,
      body: SafeArea(
        child: Stack(
          children: <Widget>[
            Center(child: SomeOtherCustomWidget())
          ],
        )
      ),
    );
  }
}

运行应用程序时,可以正确看到导航栏和抽屉。我可以单击抽屉中的链接在我的页面之间导航。但是,每次我导航到页面时,该页面上的所有小部件都会重置为其初始状态。我想确保小部件不会重置。另一种思考方式是:我只希望在应用程序的整个生命周期中每个页面的一个实例,而不是每当用户导航到它们时都创建它们的新实例。

我尝试创建触发onTap事件时Drawer使用的Page1的静态实例,但这不起作用。我在想这个吗?我需要转换为有状态的小部件吗?

1 个答案:

答案 0 :(得分:1)

哦,你要请客了……这会很长(抱歉),但是请在决定和采取行动之前先阅读所有内容-我保证可以节省您的时间。

有很多解决此问题的方法,但是总的来说,您要问的是状态管理(这实际上是软件工程,更多信息在这里Understanding state management, and why you never will)。

我会尽力解释您的具体情况。

问题:

Navigator视为应用程序状态的List,您可以通过其各种方法(例如pop()push()等进行操作)请注意,正在发生的事情很明显-按下按钮实际上是在删除当前状态(页面),然后紧接着按下状态的新实例(页面)。

解决方案:

正如我所说,有许多解决此问题的方法,例如,您可能会想将状态(对特定“页面”所做的更改)存储在var中,并在在“页”,在创建该页面的新实例时,但是您很快就会遇到其他问题。这就是为什么我认为没有人可以为这个问题提供简单的解决方案...

首先,我是否可以建议您阅读一些有用的信息: Flutter official docs on state management-当您进入本文的“选项”部分时,有趣的部分开始了,并且很快就会变得势不可挡,但请不要担心:P

请务必也阅读答案开头提到的中篇文章,我发现它确实很有帮助。

这些内容足以帮助您做出决定,此外,在中型和YouTube视频上还有很多文章涉及Flutter的状态管理问题(甚至有一些来自框架作者)-搜索“使用Flutter进行状态管理”。

现在是我个人的意见

如果这是一个非常简单的用例,并且您不打算进行扩展(请相信我,这几乎是不可能的),则可以将StatefulWidgetsetState()结合使用,也许InheritedWidget(用于将依赖项注入树中,或者像React的人一样称其为“ lifting state up”)。或者代替上面的内容,也许看看scoped_model,它可以为您抽象所有这些内容(因此,我还没有玩过)。

我现在在一个实际项目中使用的是blocflutter_bloc(BLoC =业务逻辑组件),我将不对其进行详细介绍,但基本上它采用了scoped_model更进一步,而不会使抽象过度复杂。 bloc负责抽象出应用程序的“业务逻辑”,flutter_bloc负责在用户界面中“注入”状态并对状态变化做出反应(在此问题上,Flutter的官方立场是{{3 }})。 BLoC具有输入和输出,它将事件作为输入(可以是用户输入,或者实际上是任何类型的事件),并产生状态。总结一下,就是blocUI = f(State)是上手的好方法。 我强烈推荐它。请仔细阅读所有内容。

(ps这可能是我个人的观点,但最终,Flutter的状态管理全部基于某种形式,使用InheritedWidgetsetState()来响应用户输入或其他外部应该改变应用程序状态的因素,所以我认为BLoC模式确实可以抽象那些:P)