Preserving state between tab view pages

25,403

Solution 1

Long story short, use a PageStorageKey() for your ListView or one of it's ancestors, the Container widget in your case:

child: Container(
    key: PageStorageKey(page.country),
    child: Newsfeed(country: page.country),
),

See details here:

Solution 2

In case you want to keep the state of your screen in your TabBarView, you can use the mixin class called AutomaticKeepAliveClientMixin in your State class.

After that you have to override the wantKeepAlive method and return true.

I wrote a post about that here: https://medium.com/@diegoveloper/flutter-persistent-tab-bars-a26220d322bc

Solution 3

Use of the mixin and AutomaticKeepAliveClientMixin on our State.

Implement bool get wantKeepAlive => true; and don't forget to call super.build(context); in your build function

class ResidentListScreen extends StatefulWidget {
  @override
  _ResidentListScreenState createState() => _ResidentListScreenState();
}

class _ResidentListScreenState extends State<ResidentListScreen> with 
AutomaticKeepAliveClientMixin<ResidentListScreen>{

  @override
  bool get wantKeepAlive => true;

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

  @override
  Widget build(BuildContext context) { 
    super.build(context);
  }
}
Share:
25,403
Colin Ricardo
Author by

Colin Ricardo

https://github.com/colinricardo

Updated on July 09, 2022

Comments

  • Colin Ricardo
    Colin Ricardo almost 2 years

    issue

    I have two ListViews rendering inside of a TabBarView using a TabController.

    How do I preserve state (for lack of a better word) between each ListView so that: 1.) the Widgets don't rebuild and 2.) the ListView position is remembered between tabs.

    relevant code

    class AppState extends State<App> with SingleTickerProviderStateMixin {
      TabController _tabController;
    
      @override
      void initState() {
        super.initState();
        _tabController = new TabController(
          vsync: this,
          length: _allPages.length,
        );
      }
    
      @override
      void dispose() {
        _tabController.dispose();
        super.dispose();
      }
    
      Widget _buildScaffold(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('headlines'),
            bottom: new TabBar(
                controller: _tabController,
                isScrollable: true,
                tabs: _allPages
                    .map((_Page page) => new Tab(text: page.country))
                    .toList()),
          ),
          body: new TabBarView(
              controller: _tabController,
              children: _allPages.map((_Page page) {
                return new SafeArea(
                  top: false,
                  bottom: false,
                  child: new Container(
                    key: new ObjectKey(page.country),
                    child: new Newsfeed(country: page.country),
                  ),
                );
              }).toList()),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'news app',
          home: _buildScaffold(context),
        );
      }
    }
    

    illustrating gif

    https://media.giphy.com/media/2ysWhzqHVqL1xcBlBE/giphy.gif

  • perrohunter
    perrohunter over 5 years
    Will this keep only 1 attribute stored?
  • egorikem
    egorikem about 4 years
    Definitely the best approach by a great margin
  • nipunasudha
    nipunasudha almost 4 years
    Please take a look below for a better solution from @diegoveloper
  • CybeX
    CybeX almost 3 years
    this should be the suggested answer!
  • diegoveloper
    diegoveloper almost 3 years
    I have a video about this youtube.com/watch?v=3v4ZofYsn5I in spanish but you can enable english subtitles.