【问题标题】:Losing widget state when switching pages in a Flutter PageView在 Flutter PageView 中切换页面时丢失小部件状态
【发布时间】:2017-08-29 17:13:48
【问题描述】:

我在由 PageController 管理的 PageView 中有一系列有状态的小部件。我正在使用pageController.jumpToPage(index) 切换页面。切换页面时,小部件中的所有状态似乎都丢失了,就好像它是从头开始重新创建的。我曾尝试在 PageController 中使用keepPage: true,但这似乎没有任何效果。这是 PageView 的预期行为还是我做错了什么?任何建议表示赞赏,谢谢!

【问题讨论】:

    标签: flutter


    【解决方案1】:

    与 AutomaticKeepAliveClientMixin 一起使用到您的子页面。

    然后@override bool get wantKeepAlive => true; 这是一个示例

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return DefaultTabController(
          length: 4,
          child: new Scaffold(
            appBar: new AppBar(
              bottom: new TabBar(
                tabs: [
                  new Tab(icon: new Icon(Icons.directions_car)),
                  new Tab(icon: new Icon(Icons.directions_transit)),
                  new Tab(icon: new Icon(Icons.directions_bike)),
                  new Tab(
                    icon: new Icon(Icons.airplanemode_active),
                  )
                ],
              ),
            ),
            body: new TabBarView(children: [
              new OnePage(color: Colors.black,),
              new OnePage(color: Colors.green,),
              new OnePage(color: Colors.red,),
              new OnePage(color: Colors.blue,),
            ]),
          ),
        );
      }
    }
    
    class OnePage extends StatefulWidget {
      final Color color;
    
      const OnePage({Key key, this.color}) : super(key: key);
    
      @override
      _OnePageState createState() => new _OnePageState();
    }
    
    class _OnePageState extends State<OnePage> with AutomaticKeepAliveClientMixin<OnePage> {
      @override
      Widget build(BuildContext context) {
        super.build(context);
        return new SizedBox.expand(
          child: new ListView.builder(
            itemCount: 100,
            itemBuilder: (context, index) {
              return new Padding(
                padding: const EdgeInsets.all(10.0),
                child: new Text(
                  '$index',
                  style: new TextStyle(color: widget.color),
                ),
              );
            },
          ),
        );
      }
    
      @override
      bool get wantKeepAlive => true;
    }
    

    【讨论】:

    【解决方案2】:

    keepPage: true 是默认行为;这意味着如果PageController 被销毁并重新创建,它将记住它所在的页面。这不是你想要的。

    相反,将特定于页面的PageStorageKey 传递给页面的构造函数。这有助于 Flutter 为您的页面提供一个独特的存储桶。然后在您想要恢复到以前状态的State 中,您可以使用PageStorage.of(context) 获取存储桶,您可以将initStatewrite 值中的read 值更改为它们更改时的值.您可以在ExpansionTile 中查看示例。

    【讨论】:

    • 这似乎很奇怪,这是必需的。因此,我应该将每个小部件的滚动位置保存在 PageView 中,或者保存导航堆栈(如果存在的话)和类似的东西?当我翻页时,有没有办法让小部件保持原样?我应该提一下,我的 PageView 中的一个小部件不会在您翻页时失去它的状态,所以可能只是我在做一些愚蠢的事情。
    • 滚动位置由框架内部维护,参见ScrollPosition classPageStorage的用法。如果正在维护其他状态,可能是因为它存储在树的更高级别。
    • 谢谢,为包含 ListView 的小部件设置 PageStorage 键似乎在保存滚动位置方面起到了作用。我必须承认,当状态的其余部分非常自动化时,为什么手动存储部分状态是必要的,这对我来说仍然很困惑。我想我不明白为什么 StatefulWidget 创建的状态对象不只是存储然后自动重用。
    • PageViews 可能有无限的页面,因此 Flutter 需要一些机制来清理屏幕外页面。
    • 我知道 PageView 可以有多个页面,就像 ViewPager 但 ViewPager 为您提供了一个功能,您可以在其中定义要在内存中保留多少页。我相信我们在 PageView 中需要类似的东西。这太过分了,尤其是当我从后端下载数据时,所以我需要进行更多检查,以免每次都获取数据。
    【解决方案3】:

    编写自定义小部件:

    import 'package:flutter/material.dart';
    
    class KeepAlivePage extends StatefulWidget {
      KeepAlivePage({
        Key key,
        @required this.child,
      }) : super(key: key);
    
      final Widget child;
    
      @override
      _KeepAlivePageState createState() => _KeepAlivePageState();
    }
    
    class _KeepAlivePageState extends State<KeepAlivePage>
        with AutomaticKeepAliveClientMixin {
      @override
      Widget build(BuildContext context) {
        /// Dont't forget this
        super.build(context);
    
        return widget.child;
      }
    
      @override
      // TODO: implement wantKeepAlive
      bool get wantKeepAlive => true;
    }
    

    并在浏览量中使用:

    import 'package:flutter/material.dart';
    import 'keep_alive_page.dart';
    class PageViewDemo extends StatefulWidget {
      const PageViewDemo({Key key}) : super(key: key);
    
      @override
      _PageViewDemoState createState() => _PageViewDemoState();
    }
    
    class _PageViewDemoState extends State<PageViewDemo> {
      @override
      Widget build(BuildContext context) {
        return PageView(
          children: [
            KeepAlivePage(child:Page1()),
            KeepAlivePage(child: Page2()),
            KeepAlivePage(child:Page3()),
          ],
        );
      }
    }
    

    【讨论】:

    • super.build(context),这是我丢失的关键,谢谢。
    猜你喜欢
    • 2018-11-13
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    相关资源
    最近更新 更多