欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flutter页面切换状态维持

程序员文章站 2022-06-29 18:34:19
...

在flutter中,使用类似于PageView进行页面切换时,如果不做处理,不会保持页面原状态。也就是从A页面切换到B页面,再从B页面切回到A页面,A页面显示都会重新加载。如果A页面加载比较耗时(例如有网络请求),就会带来不好的用户体验。如下图所示,页面已经加载过了,再次切换时还会重新加载。
Flutter页面切换状态维持
最终,我们想要的效果是页面第一次加载会进行网络请求,当再次切换回到该页面时,希望维持原状态不变,效果如下图所示:
Flutter页面切换状态维持

一、TabBar+TabBarView的页面切换状态维持

方法:使用AutomaticKeepAliveClientMixin
在TabBarView(也可以用PageView)每个子页面的State类实现AutomaticKeepAliveClientMixin接口,然后在子页面的State类重写wantKeepAlive为true即可。
注意点:State类build方法中要添加super.build(context);不然会出现某些页面切换没有维持原状态。
例如:

class PersonEventList extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _PersonEventListState();
  }
}
class _PersonEventListState extends State<PersonEventList>
    with AutomaticKeepAliveClientMixin {
  //导航栏切换时保持原有状态
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext mContext) {
    super.build(context);
    return ......
    .............
}}

二、底部导航栏切换时维持原状态

Flutter中底部导航栏一般使用BottomAppBar或者BottomNavigationBar组件来实现,要想维持页面切换维持原状态,如下图所示,也要做一些处理:
Flutter页面切换状态维持

2.1 使用IndexedStack

IndexedStack继承自Stack,它可以叠堆多个组件,并通过index来控制指定的组件显示。我们只需要用这个Widget将body中的子页面包裹就能达到目的。

class _HomeRouteState extends State<HomeRoute> {
   var _position = 0;
   List<Widget> _pageList = List();
    _pageList.add(RepoListRoute());
    _pageList.add(RepoHistoryPage());
    _pageList.add(TrendRoute());
    _pageList.add(PersonDetailPage());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: _buildBottomAppBar(),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      body: IndexedStack(
          index: _position,
          children: _pageList,
        ),
      ...........

2.2 使用Offstage实现

Offstage可容纳一个子组件,可更改其消失与否,当offstage属性为true时,子组件会消失。实现的原理与IndexedStack相同。

class _HomeRouteState extends State<HomeRoute> {
   var _position = 0;
   List<Widget> _pageList = List();
    _pageList.add(RepoListRoute());
    _pageList.add(RepoHistoryPage());
    _pageList.add(TrendRoute());
    _pageList.add(PersonDetailPage());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: _buildBottomAppBar(),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      body:  Stack(
  children: [
    Offstage(
      offstage: _position != 0,
      child: _pageList[0],
    ),
    Offstage(
      offstage: _position != 1,
      child: _pageList[1],
    ),
    Offstage(
      offstage: _position != 2,
      child: _pageList[2],
    ),
  ],
),
      ...........

上面两种方式都能实现保持原页面状态,原理相同。但是,在第一次加载时,所有子页面都被实例化了,开销较大。所以可以采用下面第三种方式。

2.3 PageView + AutomaticKeepAliveClientMixin方式

body使用PageView来容纳所有子页面,在底部BottomAppBar的item点击时通过PageView的Controler实现页面切换,然后每个子页面继承AutomaticKeepAliveClientMixin即可。

三、项目介绍

以上例子在下面这个项目中都有体现:
项目地址:用flutter实现的一款界面精美的Github App
介绍:用Flutter实现的一款界面精美、功能较全、体验良好的Github客户端。支持多语言、换肤等功能。代码简单易懂且有充分的注释,很适用于学习Flutter。