Flutter: dynamically add tabs and keep state with AutomaticKeepAliveClientMixin

2,283

You forgot to add super.build(context); as the documentation of AutomaticKeepAliveClientMixin suggests.

@override
  Widget build(BuildContext context) {
    super.build(context);
    return Tab(
      child: TextFormField(
        decoration: InputDecoration(labelText: widget.tabData.name),
        initialValue: widget.tabData.data,
      ),
    );
  }
Share:
2,283
Oleg Plotnikov
Author by

Oleg Plotnikov

Updated on December 08, 2022

Comments

  • Oleg Plotnikov
    Oleg Plotnikov over 1 year

    I'm trying to create a form with tabs. In each tab I have TextFormField. Tabs have AutomaticKeepAliveClientMixin to keep their State. Tabs can be created dynamically. When new tab is created, it is inserted in the middle of the tabs list.

    Problem: when new tab is inserted, its TextFormField keep state of the next tab and so on. It seems states keeps in order from 1 to n. Is there any way to keep the right state for tabs?

    Thanks in advance.

    import 'package:flutter/material.dart';
    
    class TabTesting extends StatefulWidget {
      @override
      _TabTestingState createState() => _TabTestingState();
    }
    
    class _TabTestingState extends State<TabTesting> with TickerProviderStateMixin {
    
      List<MyTab> _tabs = [
          MyTab(TabData("1", "1")),
          MyTab(TabData("3", "3")),
      ];
    
      TabController _tabController;
    
      @override
      void initState() {
        super.initState();
    
        _tabController = new TabController(vsync: this, length: _tabs.length);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("TabTesting"),
            bottom: TabBar(
              controller: _tabController,
              labelPadding: EdgeInsets.symmetric(vertical: 16.0),
              tabs: _tabs.map((tab) => Text(tab.tabData.name)).toList(),
            ),
          ),
          body: Container(
            padding: EdgeInsets.all(32.0),
            child: TabBarView(
              controller: _tabController,
              children: _tabs,
            ),
          ),
          persistentFooterButtons: <Widget>[
            RaisedButton(
              child: Text("Add tab"),
              onPressed: () {
                final newTab = MyTab(TabData("2", "2"));
                final newTabs = _tabs;
                newTabs.insert(1, newTab);
                final index = _tabController.index;
                setState(() {
                  _tabs = newTabs;             
                  _tabController = TabController(
                      vsync: this,
                      length: newTabs.length,
                      initialIndex: index);
                });
              },
            ),
          ],
        );
      }
    }
    
    class MyTab extends StatefulWidget {
    
      final tabData;
    
      MyTab(this.tabData);
    
      @override
      _MyTabState createState() => _MyTabState();
    }
    
    class _MyTabState extends State<MyTab> with AutomaticKeepAliveClientMixin {
    
      @override
      bool get wantKeepAlive => true;
    
      @override
      Widget build(BuildContext context) {
        return Tab(
          child: TextFormField(
            decoration: InputDecoration(labelText: widget.tabData.name),
            initialValue: widget.tabData.data,
          ),
        );
      }
    }
    
    class TabData {
      String name;
      String data;
    
      TabData(this.name, this.data);
    }