1

How do I add tabs dynamically to the TabBar Widget in Flutter? The list of tabs is fetched from the internet using a REST API.

When I fetch the list using the code below I get the following errors:

RangeError (index): Invalid value: Only valid value is 0: 1

A RenderFlex overflowed by 99896 pixels on the bottom.

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  Future<List<Categories>> categoriesList;

  final categoryTabs = <Tab>[
    Tab(text: 'Home'),
  ];

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

    categoriesList = NewsServices.fetchCategoriesList(lang: 'en');
    categoriesList.then((categories) {
      categories.forEach((category) {
        setState(() {
          categoryTabs.add(Tab(
            text: category.name,
          ));
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: categoryTabs.length,
      child: Scaffold(
        appBar: AppBar(
          title: Text('Example App'),
          bottom: TabBar(
            isScrollable: true,
            tabs: categoryTabs,
          ),
        ),
        body: SafeArea(...),
        ),
      ),
    );
  }

App demo for the error on iOS simulator

0

1 Answer 1

4

You have to iterate the list which you achieved from the REST API.

Suppose, we declare a list of String which you will get from the REST API.

List<String> tabTextList;

Then declare the list of tabs.

List<Tab> _tabs = List<Tab>();

Then iterate the list of strings.

List<Tab> getTabs() {
    _tabs.clear();
    for (int i = 0; i < tabTextList.length; i++) {
      _tabs.add(getTab(i));
    }
    return _tabs;
  }

  Tab getTab(int widgetNumber) {
    return Tab(
      text: "${tabTextList[widgetNumber]}",
    );
  }

Then the build function will be like this.

@override
 Widget build(BuildContext context) {
   return Scaffold(
      body: DefaultTabController(
        length: tabTextList.length,
        child: Scaffold(
          
            bottom: TabBar(
              isScrollable: true,
              tabs: getTabs(),
            ),
          ),
          
          body: Container(),
        ),
      ),
    );
 }

According to your updated code you have to change some portion.

Use another variable categoryTabsTemp to store the array temporarily. After that you have to use setState to update the categoryTabs and rebuild. The updated code should be like that.

var categoryTabs = <Tab>[
    Tab(text: 'Home'),
  ];

  var categoryTabsTemp = <Tab>[
    Tab(text: 'Home'),
  ];

  @override
  void initState() {
    super.initState();
    categoriesList = NewsServices.fetchCategoriesList(lang: 'en');
    categoriesList.then((categories) {
      categories.forEach((category) {
        categoryTabsTemp.add(Tab(
          text: category.name,
        ));
      });
      setState(() {
        categoryTabs = categoryTabsTemp;
      });
    });
  }
Sign up to request clarification or add additional context in comments.

3 Comments

Hi, thanks for the answer. I have one problem the list initially has no items, how do I rebuild the TabBar after the list is fetched?
Hi, You can call setState after getting items. setState will rebuild the page and also TabBar.
Thanks, but when I do so I get the following error in the updated question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.