Динамически Таббар Флаттер - PullRequest
       28

Динамически Таббар Флаттер

0 голосов
/ 24 сентября 2019

Если я хочу, чтобы пользователь добавил / удалил вкладки на панели вкладок, как я могу сделать это динамически?

Пока я могу создать новую вкладку, но не могу перейти на нужную страницу при создании.

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 => colors != null ? colors.shade300 :     Colors.grey.shade300;
  bool get fabDefined => colors != null && iconfloatingbutton != null;
  Color get fabColor => colors.shade400;
  Icon get fabIcon => Icon(iconfloatingbutton);
  Key get fabKey => ValueKey<Color>(fabColor);
}

final List<_Page> _allPages = <_Page>[
  _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() => _TabsFabDemoState();
}

class _TabsFabDemoState extends State<TabsFabDemo> 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) => Tab(text: _allPages[index].label),
            pageBuilder: (context, index) => Container(color:Colors.white,child: Text(_allPages[index].label)),
            onPositionChange: (index){
              print('current position: $index');
            },
            onScroll: (position) => 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));
    });
  }


}

// --------------------- РЕАЛИЗАЦИЯ ПОЛЬЗОВАТЕЛЬСКОЙ TABBAR ------------------

class CustomTabView extends StatefulWidget {
  final int itemCount;
  final IndexedWidgetBuilder tabBuilder;
  final IndexedWidgetBuilder pageBuilder;
  final Widget stub;
  final ValueChanged<int> onPositionChange;
  final ValueChanged<double> 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() => _CustomTabsState();
}

class _CustomTabsState extends State<CustomTabView> 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 > widget.itemCount - 1) {
        print("DID UPDATE POSITION : 2");

        _currentPosition = widget.itemCount - 1;
        _currentPosition = _currentPosition < 0 ? 0 :
        _currentPosition;    
        if (widget.onPositionChange is ValueChanged<int>) {
          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 < 1) return widget.stub ?? Container();

    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: <Widget>[
        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) => widget.tabBuilder(context, index),
            ),
          ),
        ),
        Expanded(
          child: TabBarView(
            controller: controller,
            children: List.generate(
              widget.itemCount,
                  (index) => widget.pageBuilder(context, index),
            ),
          ),
        ),
      ],
    );
  }

  onPositionChange() {
    if (!controller.indexIsChanging) {
      _currentPosition = controller.index;
      if (widget.onPositionChange is ValueChanged<int>) {
        widget.onPositionChange(_currentPosition);
      }
    }
  }

  onScroll() {
    if (widget.onScroll is ValueChanged<double>) {
      widget.onScroll(controller.animation.value);
    }
  }
}

Когда я создаю вкладку, прокрутка должна указывать нановый сгенерированный элемент

Когда я удаляю вкладку, свиток должен указывать на предыдущий элемент

1 Ответ

0 голосов
/ 24 сентября 2019

Чтобы динамически добавлять или удалять вкладки, вам нужно вызвать методы add или delete внутри setState () вашего Widget с отслеживанием состояния.

Чтобы переместить контроллер на вновь добавленную вкладку, просто обновитеinitPosition для недавно добавленного индекса вкладки, как показано ниже.Я только что изменил ваш класс TabsFabDemo, так как остальная часть вашего кода в порядке (реализация классов CustomTabBar и _Page).

class TabsFabDemo extends StatefulWidget {
   @override
  _TabsFabDemoState createState() => _TabsFabDemoState();
}

class _TabsFabDemoState extends State<TabsFabDemo>
    with SingleTickerProviderStateMixin {
  int initPosition = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: CustomTabView(
          initPosition: initPosition,
          itemCount: data.length,
          tabBuilder: (context, index) => Tab(text: data[index].label),
          pageBuilder: (context, index) =>
              Center(child: Text(data[index].label)),
          onPositionChange: (index) {
            initPosition = index;
          },
          onScroll: (position) => print('$position'),
        ),
      ),
      floatingActionButton: Container(
        height: 130.0,
        width: 80.0,
        child: FloatingActionButton(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              IconButton(
                icon: Icon(Icons.add),
                onPressed: () {
                  setState(() {
                    data.add(_Page(
                        label: 'Blue',
                        colors: Colors.indigo,
                        iconup: Icons.satellite,
                        iconfloatingbutton: Icons.add));

                    int lastIndex = data.length;
                    initPosition = lastIndex;
                  });
                },
                padding: const EdgeInsets.all(0.0),
              ),
              IconButton(
                icon: Icon(Icons.remove),
                onPressed: () {
                  setState(() {
                    data.removeLast();
                  });
                },
                padding: const EdgeInsets.all(0.0),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
...