ListView恢复滚动位置

时间:2019-06-29 15:42:59

标签: flutter

如果我使用PageView(内部带有ListView)+ BottomNavBar,则一切正常。 我对每个页面都使用唯一的PageStorageKey,因此两个页面上的ListViews都可以保存和恢复滚动偏移。

但是我需要基于路线构建应用程序导航。 这是一个非常简化的代码,但这足以显示和重现我所遇到的问题。 您可以复制并粘贴此片段,然后检查

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(title: Text("Test")),
        body: Scaffold(
          body: Navigator(
            key: _navigatorKey,
            onGenerateRoute: (settings) {
              switch (settings.name) {
                case '/':
                  return MaterialPageRoute(builder: (_) => SomeWidget(0));
                case '/another_route':
                  return MaterialPageRoute(builder: (_) => SomeWidget(1));
                  break;
              }
            },
          ),
          bottomNavigationBar: BottomNavigationBar(
            selectedItemColor: Colors.grey,
            unselectedItemColor: Colors.grey,
            items: [
              BottomNavigationBarItem(icon: Icon(Icons.print), title: Text('Page 0')),
              BottomNavigationBarItem(icon: Icon(Icons.category), title: Text('Page 1')),
            ],
            onTap: (index) {
              if (index == 0) {
                _navigatorKey.currentState.pushReplacementNamed('/');
              } else {
                _navigatorKey.currentState.pushReplacementNamed('/another_route');
              }
            },
          ),
        ),
      ),
    );
  }
}

class SomeWidget extends StatelessWidget {
  final int page;

  SomeWidget(this.page) : super(key: Key('page key $page'));

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      key: PageStorageKey(page),
      itemBuilder: (context, index) {
        return Card(
          key: Key('item: $index on page: $page'),
          color: page == 0 ? Colors.blue[200] : Colors.green[200],
          child: Container(
            height: 196,
            alignment: Alignment.center,
            child: Text('Row: $index  |  Page $page'),
          ),
        );
      },
    );
  }
}

PS:出于某些原因,我不想为此使用PageView。我相信BottomNavBar应该触发本地导航器以替换不同的页面进行推送。

我认为这是非常方便的方式,而且我可以轻松更改页面之间的导航过渡。在我的情况下,我使用FadeIn +比例转换,但是在上面的示例代码中,我忽略了这一点,因为它不会影响最终结果。

是的,我了解PageStorageKey,但是它无济于事。

这也是视频,您可以明白我的意思。当我按一下botton栏中的第一个图标时,我会看到列表,但它无法恢复滚动位置。 enter image description here

1 个答案:

答案 0 :(得分:0)

这是预期的行为。按下屏幕时,它将构建一个全新的屏幕,而没有任何以前的状态。

这就是为什么使用综合浏览量的原因,它是为了保留状态而不会卸载任何屏幕。

在您的示例中,生命周期为

  1. 布置屏幕

  2. 构建新屏幕

  3. 显示屏幕

我可以共享我的使用方式,而无需使用viewpager(因为我不需要拖动功能)。

import 'package:flutter/material.dart';
import '../Widgets.dart'; // my custom widgets

class PageTabs extends StatefulWidget {
  @override
  _PageTabsState createState() => _PageTabsState();
}

class _PageTabsState extends State<PageTabs> {
  int _cIndex = 0; //the current page index

  @override
  void initState() {
    super.initState();
  }

  void _changeTab(index) {
    setState(() {
      _cIndex = index;
    });
  }

  List<Widget> tabs = [
    TimelineScreen(key: PageStorageKey('TimeLine')),
    PageTrends(key: PageStorageKey('Trends')),
    PageSettings(key: PageStorageKey('Settings'))
  ];
  final PageStorageBucket bucket = PageStorageBucket();



  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
        initialIndex: 1,
        length: 3,
        child: Stack(
          alignment: AlignmentDirectional.bottomStart,
          children: <Widget>[
          PageStorage(
              child: tabs[_cIndex],
              bucket: bucket,
            ),
           AppBarra( //Custom bottom navigation bar wrapper
                child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: <Widget>[
                  Expanded(
                      child: TabButton(
                          tooltip: 'Back',
                          onTap: () {
                            _changeTab(0);
                          },
                          icon: Icons.home,
                          color:
                              _cIndex == 0 ? Color(0xff00abee) : Colors.grey)),
                  Expanded(
                      child: TabButton(
                          tooltip: 'Back',
                          onTap: () {
                            _changeTab(1);
                          },
                          icon: Icons.search,
                           color:
                              _cIndex == 1 ? Color(0xff00abee) : Colors.grey)
                      ),
                  Expanded(
                      child: TabButton(
                          tooltip: 'Back',
                          onTap: () {
                            _changeTab(2);
                          },
                          icon: Icons.settings,
                          color:
                              _cIndex == 2 ? Color(0xff00abee) : Colors.grey)),
                ]))
          ]


    ));
  }
}

我使用pageStorage来保存状态,使用堆栈以避免使用脚手架(因为在页面中放置另一个脚手架时会导致奇怪的颜色错误),并使用自定义应用栏为我完成一些样式设置(自定义材质标高阴影颜色]。

您可以尝试自己弄清楚它,这里的重要部分是一起使用pageStorage,存储桶和PageStorageKey来保留滚动位置