Flutter-在应用程序的整个生命周期内保持页面静态? [英] Flutter - Keep page static throughout lifecycle of app?

查看:83
本文介绍了Flutter-在应用程序的整个生命周期内保持页面静态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have created an AppDrawer widget to wrap my primary drawer navigation and reference it in a single place, like so:

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和主体:

I have also created a custom AppScaffold widget, which simply returns a consistent AppBar, my custom AppDrawer, and body:

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.它们现在很简单,看起来像这样:

I have created two pages: Page1, and Page2. They are simple right now, and look something like this:

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())
          ],
        )
      ),
    );
  }
}

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

When I run my app, I can see the navbar and drawer correctly. I can click on the links in the drawer to navigate between my pages. However, each time I navigate to a page, all of the widgets on that page get reset to their initial state. I want to ensure that the widgets do not get reset. Another way to think of this is: I only want one instance of each page throughout the lifecycle of the app, instead of creating them new whenever a user navigates to them.

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

I tried creating a static instance of Page1 that the Drawer uses when the onTap event is fired, but this does not work. Am I thinking about this incorrectly? Do I need to convert to a Stateful widget?

推荐答案

哦,您可以请客...这会很长(很抱歉),但是在做出决定和采取行动之前,请仔细阅读所有内容-我保证可以节省您的时间.

Oh, you're in for a treat... This will be kinda long (sorry) but please read all of it before making decisions and taking action - I promise I am saving you time.

有许多不同的解决方案来解决此问题,但总的来说,您要问的是状态管理(这实际上是软件工程,更多信息请参见-

There are many different solutions to this problem, but in general what you're asking about is state management (which is really software engineering, more info here - Understanding state management, and why you never will).

我将尽力解释您的具体情况.

I'll try my best to explain what is happening in your specific case...

问题:

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

Think of Navigator as a List of application states, which you can manipulate via its various methods (i.e. pop(), push(), etc.), with this in mind it is clear what is happening - on a button press you're actually removing the current state (page) and right after that you're pushing a new instance of your state (page).

解决方案:

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

As I said, there are many solutions to this problem, for example, you may be tempted to store the state (the changes you made to a particular "page") somewhere in a var and inject that var when navigating between "pages", when creating a new instance of that page, but you'll soon run into other problems. This is why I don't think anyone can provide a simple solution to this problem...

首先,我可以建议您阅读一些有用的信息: 关于状态管理的官方文档-当您进入在选项"部分,有趣的部分开始了,很快就会变得势不可挡,但不要担心:P

First, may I suggest you some useful reads on the matter: Flutter official docs on state management - When you get to the "Options" section of this, the fun part begins and can quickly get overwhelming, but fear not :P

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

Be sure to read the medium article mentioned in the start of my answer too, I found it really helpful.

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

These reads will be more than enough to help you make a decision, plus there are a ton of articles on Medium and YouTube videos touching on the matter of state management with Flutter (even some from the authors of the framework) - just search for "State management with Flutter".

现在是我个人的意见:

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

If it's a really simple use case and you don't plan to grow (which is almost never the case, trust me), you can just use StatefulWidgets in combination with setState() and maybe InheritedWidget (for dependency injection down the tree, or like React guys call it "lifting state up"). Or instead of the above, maybe have a look at scoped_model, which kinda abstracts all of this for you (tho, I haven't played with it).

我现在在现实世界中使用的项目是 bloc flutter_bloc (BLoC =业务逻辑组件),我不会详细介绍它,但是基本上它需要scoped_model的想法又向前迈进了一步,而又没有使抽象复杂化. bloc负责抽象出应用程序的业务逻辑",并flutter_bloc负责在用户界面中注入"状态并对状态更改做出反应(在此问题上,Flutter的官方立场是 BLoC的官方文档. 我强烈推荐它.请仔细阅读所有内容.

What I use right now for a real world project is bloc and flutter_bloc (BLoC = Business Logic Component), I will not get into the details of it, but basically it takes the idea of scoped_model one step further, without over-complicating abstractions. bloc is responsible for abstracting away the "business logic" of your application and flutter_bloc to "inject" the state in your UI and react to state changes (official Flutter position on the matter is that UI = f(State)). A BLoC has an input and an output, it takes in events as an input (can be user input, or other, any type of event really) and produces a state. In summary that's it about bloc. A great way to get started is BLoC's official documentation. I highly recommend it. Just go through everything.

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

(p.s. This may be my personal opinion, but in the end state management in Flutter is all based on some form of using InheritedWidget and setState() in response to user input or other external factors that should change the application state, so I think the BLoC pattern is really on point with abstracting those :P)

这篇关于Flutter-在应用程序的整个生命周期内保持页面静态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆