title: Dynamically Tabbar Flutter
body: <p>if I wanted the user to add / remove tabs on tabbar, how can I do it dynamically ? </p>
  
  <p>For now i can create a new tab but i can' t skip to the right page when create.</p>
  
  <pre><code>class _Page {
    _Page({ this.label, this.colors, this.iconup,this.iconfloatingbutton });
  
    final String label;
    final MaterialColor colors;
    final IconData iconfloatingbutton;
    final IconData iconup;
  
    Color get labelColor =&gt; colors != null ? colors.shade300 :     Colors.grey.shade300;
    bool get fabDefined =&gt; colors != null &amp;&amp; iconfloatingbutton != null;
    Color get fabColor =&gt; colors.shade400;
    Icon get fabIcon =&gt; Icon(iconfloatingbutton);
    Key get fabKey =&gt; ValueKey&lt;Color&gt;(fabColor);
  }
  
  final List&lt;_Page&gt; _allPages = &lt;_Page&gt;[
    _Page(label: 'Blue', colors: Colors.indigo,iconup:Icons.text_fields,     iconfloatingbutton: Icons.add),
    _Page(label: 'Eco', colors: Colors.green,iconup:Icons.text_fields, iconfloatingbutton: Icons.create),
    _Page(label: 'No',iconup:Icons.text_fields,),
    _Page(label: 'Teal', colors: Colors.teal,iconup:Icons.text_fields, iconfloatingbutton: Icons.add),
  
  ];
  
  class TabsFabDemo extends StatefulWidget {
  
    @override
    _TabsFabDemoState createState() =&gt; _TabsFabDemoState();
  }
  
  class _TabsFabDemoState extends State&lt;TabsFabDemo&gt; with     SingleTickerProviderStateMixin {
  
  
    int initPosition = 1;
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Container(
          color: Colors.green,
          child: SafeArea(
            child: CustomTabView(
              initPosition: initPosition,
              itemCount: _allPages.length,
              tabBuilder: (context, index) =&gt; Tab(text: _allPages[index].label),
              pageBuilder: (context, index) =&gt; Container(color:Colors.white,child: Text(_allPages[index].label)),
              onPositionChange: (index){
                print('current position: $index');
              },
              onScroll: (position) =&gt; print("POS : "+'$position'),
            ),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            addtab("a",null);
          },
          child: Icon(Icons.add),
        ),
      );
    }
  
  
    addtab(label,icon){
      setState(() {
        _allPages.add(new _Page(label: 'Blue', colors: Colors.indigo,iconup:Icons.satellite, iconfloatingbutton: Icons.add));
      });
    }
  
  
  }
  </code></pre>
  
  <p>// --------------------- IMPLEMENTATION CUSTOM TABBAR ------------------</p>
  
  <pre><code>class CustomTabView extends StatefulWidget {
    final int itemCount;
    final IndexedWidgetBuilder tabBuilder;
    final IndexedWidgetBuilder pageBuilder;
    final Widget stub;
    final ValueChanged&lt;int&gt; onPositionChange;
    final ValueChanged&lt;double&gt; onScroll;
    final int initPosition;
  
    CustomTabView({
      @required this.itemCount,
      @required this.tabBuilder,
      @required this.pageBuilder,
      this.stub,
      this.onPositionChange,
      this.onScroll,
      this.initPosition,
    });
  
    @override
    _CustomTabsState createState() =&gt; _CustomTabsState();
  }
  
  class _CustomTabsState extends State&lt;CustomTabView&gt; with         TickerProviderStateMixin {
    TabController controller;
    int _currentCount;
    int _currentPosition;
  
    @override
    void initState() {
      _currentPosition = widget.initPosition ?? 0;
      print("INIT POSITION : "+widget.initPosition.toString());
      print("INIT POSITION : "+_currentPosition.toString());
  
      controller = TabController(
        length: widget.itemCount,
        vsync: this,
        initialIndex: _currentPosition,
      );
      controller.addListener(onPositionChange);
      controller.animation.addListener(onScroll);
      _currentCount = widget.itemCount;
      super.initState();
    }
  
    @override
    void didUpdateWidget(CustomTabView oldWidget) {
  
      if (_currentCount != widget.itemCount) {
        print("DID UPDATE POSITION : 0");
  
        controller.animation.removeListener(onScroll);
        controller.removeListener(onPositionChange);
        controller.dispose();
  
        if (widget.initPosition != null) {
          print("DID UPDATE POSITION : 1");
  
          _currentPosition = widget.initPosition;
        }
  
        if (_currentPosition &gt; widget.itemCount - 1) {
          print("DID UPDATE POSITION : 2");
  
          _currentPosition = widget.itemCount - 1;
          _currentPosition = _currentPosition &lt; 0 ? 0 :
          _currentPosition;    
          if (widget.onPositionChange is ValueChanged&lt;int&gt;) {
            print("DID UPDATE POSITION : 3");
  
            WidgetsBinding.instance.addPostFrameCallback((_){
              if(mounted) {
                print("DID UPDATE POSITION : 4");
  
                widget.onPositionChange(_currentPosition);
              }
            });
          }
        }
  
  
        _currentCount = widget.itemCount;
        setState(() {
          controller = TabController(
            length: widget.itemCount,
            vsync: this,    
            initialIndex: _currentPosition,
          );
          controller.addListener(onPositionChange);
          controller.animation.addListener(onScroll);
        });
      } else if (widget.initPosition != null) {
        controller.animateTo(widget.initPosition);
      }
  
      super.didUpdateWidget(oldWidget);
    }
  
    @override
    void dispose() {
      controller.animation.removeListener(onScroll);
      controller.removeListener(onPositionChange);
      controller.dispose();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      if (widget.itemCount &lt; 1) return widget.stub ?? Container();
  
      return Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: &lt;Widget&gt;[
          Container(
            alignment: Alignment.center,
            child: TabBar(
              isScrollable: true,
              controller: controller,
              labelColor: Theme.of(context).primaryColor,
              unselectedLabelColor: Theme.of(context).hintColor,
              indicator: BoxDecoration(
                border: Border(
                  bottom: BorderSide(
                    color: Theme.of(context).primaryColor,
                    width: 2,
                  ),
                ),
              ),
              tabs: List.generate(
            widget.itemCount,
                (index) =&gt; widget.tabBuilder(context, index),
              ),
            ),
          ),
          Expanded(
            child: TabBarView(
              controller: controller,
              children: List.generate(
                widget.itemCount,
                    (index) =&gt; widget.pageBuilder(context, index),
              ),
            ),
          ),
        ],
      );
    }
  
    onPositionChange() {
      if (!controller.indexIsChanging) {
        _currentPosition = controller.index;
        if (widget.onPositionChange is ValueChanged&lt;int&gt;) {
          widget.onPositionChange(_currentPosition);
        }
      }
    }
  
    onScroll() {
      if (widget.onScroll is ValueChanged&lt;double&gt;) {
        widget.onScroll(controller.animation.value);
      }
    }
  }
  </code></pre>
  
  <p>When I create a tab the scroll must point to the new generated item</p>
  
  <p>When I delete a tab the scroll must point to the previous element</p>