Flutter 在颤振页面视图中切换页面时丢失小部件状态

Flutter 在颤振页面视图中切换页面时丢失小部件状态,flutter,Flutter,我在由PageController管理的PageView中有一系列有状态的小部件。我正在使用pageController.jumpToPage(index)切换页面。切换页面时,小部件中的所有状态似乎都丢失了,就像从头开始重新创建一样。我曾尝试在PageController中使用keepPage:true,但似乎没有任何效果。这是页面浏览的预期行为还是我做错了什么?任何建议,谢谢 keepPage:true是默认行为;这意味着PageController将记住它所在的页面,如果它被销毁并重新创建

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

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


相反,传递一个特定于页面构造函数的页面。这有助于为页面提供一个独特的存储桶。然后,在您希望恢复到以前状态的
状态中,您可以使用
PageStorage.of(context)
获取存储桶,您可以
initState
中读取
值,并在值更改时将
值写入。您可以在中看到一个示例。

与AutomaticEpaLiveClientMixin一起使用到您的子页面

然后@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;
}
导入“包装:颤振/材料.省道”;
void main()=>runApp(新的MyApp());
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回新材料PP(
标题:“颤振演示”,
主题:新主题数据(
主样本:颜色。蓝色,
),
主页:新MyHomePage(标题:“颤振演示主页”),
);
}
}
类MyHomePage扩展StatefulWidget{
MyHomePage({Key,this.title}):超级(Key:Key);
最后的字符串标题;
@凌驾
_MyHomePageState createState()=>new_MyHomePageState();
}
类_MyHomePageState扩展状态{
@凌驾
小部件构建(构建上下文){
返回DefaultTabController(
长度:4,
儿童:新脚手架(
appBar:新的appBar(
底部:新选项卡栏(
选项卡:[
新建选项卡(图标:新建图标(图标.方向\汽车)),
新建选项卡(图标:新建图标(图标.方向))),
新建选项卡(图标:新建图标(图标.方向),
新标签(
图标:新图标(图标。airplanemode_激活),
)
],
),
),
正文:新选项卡视图(子项:[
新一页(颜色:Colors.black,),
新的OnePage(颜色:Colors.green,),
新一页(颜色:Colors.red,),
新一页(颜色:Colors.blue,),
]),
),
);
}
}
类OnePage扩展了StatefulWidget{
最终颜色;
constOnePage({Key-Key,this.color}):super(Key:Key);
@凌驾
_OnePageState createState()=>new_OnePageState();
}
类_OnePageState使用AutomaticEpaLiveClientMixin扩展状态{
@凌驾
小部件构建(构建上下文){
super.build(上下文);
返回新的SizedBox.expand(
子项:新建ListView.builder(
物品计数:100,
itemBuilder:(上下文,索引){
返回新的填充(
填充:常数边集全部(10.0),
儿童:新文本(
“$index”,
样式:新文本样式(颜色:widget.color),
),
);
},
),
);
}
@凌驾
bool get wantKeepAlive=>true;
}

编写自定义小部件:

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()),
      ],
    );
  }
}
导入“包装:颤振/材料.省道”;
类KeepAlivePage扩展StatefulWidget{
保留第页({
关键点,
@需要这个孩子,
}):super(key:key);
最后一个孩子;
@凌驾
_KeepAlivePageState createState()=>\u KeepAlivePageState();
}
类_KeepAlivePageState扩展状态
使用AutomaticEpaLiveClientMixin{
@凌驾
小部件构建(构建上下文){
///别忘了这个
super.build(上下文);
返回widget.child;
}
@凌驾
//TODO:实现wantKeepAlive
bool get wantKeepAlive=>true;
}
并在页面视图中使用:

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()),
      ],
    );
  }
}
导入“包装:颤振/材料.省道”;
导入'keep_alive_page.dart';
类PageViewDemo扩展StatefulWidget{
constpageviewdemo({Key}):super(Key:Key);
@凌驾
_PageViewDemoState createState()=>\u PageViewDemoState();
}
类_PageViewDemoState扩展状态{
@凌驾
小部件构建(构建上下文){
返回页面视图(
儿童:[
KeepAlivePage(子项:Page1()),
KeepAlivePage(子项:Page2()),
KeepAlivePage(子项:Page3()),
],
);
}
}

需要这样做似乎有些奇怪。所以我应该保存页面视图中每个小部件的滚动位置,或者导航堆栈(如果存在)之类的东西?有没有一种方法可以让小部件保持在我翻页时的状态?我应该提到的是,我的PageView中的一个小部件在你翻页时不会失去它的状态,因此可能只是我在做一些总体上愚蠢的事情。滚动位置由框架内部维护,请参阅中的
PageStorage
的用法。如果保持其他状态,可能是因为它存储在树的更高级别。谢谢,为包含ListView的小部件设置PageStorage键似乎已经完成了保存滚动位置的技巧。我必须承认,我仍然很困惑,为什么手动存储状态的一部分是必要的,而状态的其余部分是如此惊人的自动。我想我不明白为什么StatefulWidget创建的状态对象不只是存储然后自动重用。PageViews可能有无限的页面,因此Flatter需要一些机制来清理屏幕外的页面。我知道PageView可以有多个页面,与ViewPager类似,但ViewPager提供了一个函数,您可以在该函数中定义要访问的页面数