Динамическое количество вкладок

#flutter #flutter-layout #tabbar

#flutter #flutter-макет #панель вкладок

Вопрос:

У меня дизайн, подобный описанному выше, моя панель вкладок находится внутри BottomNavigationBar, и я хочу разместить панель вкладок в моем меню BottomNavigationBar. Проблема в том, что я не хочу иметь вложенный каркас, и я не хочу использовать TabController потому что мои вкладки динамические, длина вкладок может уменьшаться или увеличиваться в зависимости от добавления пользователя. Если я использую TabController и определяю его внутри initState , вкладки не могут быть увеличены / уменьшены, потому что в initState значение определяется только один раз.

Как я могу это сделать?

Мое ожидание, аналогичное приведенному ниже примеру, когда я добавляю вкладку и tabMenu, оно увеличится. Но получаю эту ошибку

 The following assertion was thrown building TabBar(dirty, dependencies: [_InheritedTheme,
_LocalizationsScope-[GlobalKey#a56a4]], state: _TabBarState#fb337):
Controller's length property (2) does not match the number of tabs (3) present in TabBar's tabs
property.
The relevant error-causing widget was:
  TabBar
  

Фиктивный пример

 
class TaskScreen extends StatefulWidget {
  @override
  _TaskScreenState createState() => _TaskScreenState();
}

class _TaskScreenState extends State<TaskScreen> with SingleTickerProviderStateMixin {
  TabController _tabController;

  final List<Tab> _tab = [
    Tab(text: 'Sunday'),
    Tab(text: 'Monday'),
  ];
  final List<Widget> _tabMenu = [
    Text('This is Sunday'),
    Text('This is Monday'),
  ];

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: _tab.length, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        FlatButton(
            onPressed: () {
              setState(() {
                _tab.add(Tab(
                  text: '1',
                ));
                _tabMenu.add(Text('1'));
              });
              print('tab ${_tab.length}');
              print('tabMenu ${_tabMenu.length}');
            },
            child: Text('add')),
        Container(
          color: colorPallete.primaryColor,
          padding: EdgeInsets.only(top: sizes.statusBarHeight(context)),
          child: TabBar(
            tabs: _tab.map((e) => e).toList(),
            controller: _tabController,
          ),
        ),
        Expanded(
          child: TabBarView(
            children: _tabMenu.map((e) => e).toList(),
            controller: _tabController,
          ),
        )
      ],
    );
  }
}
  

Ответ №1:

используйте TickerProviderStateMixin вместо SingleTickerProviderStateMixin и измените TabController при изменении количества вкладок;

добавляйте isScrollable: true , когда у вас нет места для всех ваших вкладок

 import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: SafeArea(
          child: MyHomePage(),
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return TaskScreen();
  }
}

class TaskScreen extends StatefulWidget {
  @override
  _TaskScreenState createState() => _TaskScreenState();
}

class _TaskScreenState extends State<TaskScreen> with TickerProviderStateMixin {
  TabController _tabController;

  final List<Tab> _tab = [
    Tab(text: 'Sunday'),
    Tab(text: 'Monday'),
  ];
  final List<Widget> _tabMenu = [
    Text('This is Sunday'),
    Text('This is Monday'),
  ];

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: _tab.length, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        FlatButton(
            onPressed: () {
              setState(() {
                _tab.add(
                  Tab(
                    text: '1',
                  ),
                );
                _tabMenu.add(
                  Text('1'),
                );
                _tabController =
                    TabController(length: _tab.length, vsync: this);
              });
              print('tab ${_tab.length}');
              print('tabMenu ${_tabMenu.length}');
            },
            child: Text('add')),
        Container(
          color: Colors.blue,
          padding: EdgeInsets.only(top: 10),
          child: TabBar(
            // isScrollable: true, 
            tabs: _tab.map((e) => e).toList(),
            controller: _tabController,
          ),
        ),
        Expanded(
          child: TabBarView(
            children: _tabMenu.map((e) => e).toList(),
            controller: _tabController,
          ),
        )
      ],
    );
  }
}