Search code examples
flutterfirebase-realtime-databasetabstabbarcontroller

How to create Dynamic Tabs, equals to the length of list


How can I create Tabs equals to the length of a list and their name should be equals to the name of items in list and I'm fetching the list from firebase realtime database.

Here's my code:

class _ItemDetailsDemoState extends State<ItemDetailsDemo>  with SingleTickerProviderStateMixin {


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

  List<SubCategoryLoader> subCategoryLoaderList = List();

  Future<void> getSubCategories() async {
    await FirebaseDatabase.instance.reference().child("SubCategoryNames").once()
        .then((DataSnapshot snapshot) {
      var key = snapshot.value.keys;
  ;

      for (var i in key) {
        SubCategoryLoader subCategoryLoader = new SubCategoryLoader(
            snapshot.value[i]['Name']
        );
        subCategoryLoaderList.add(subCategoryLoader);
      }
      for (int j = 0; j < subCategoryLoaderList.length; j++) {
        print(subCategoryLoaderList[j].Name);
      }
      if (mounted) {
        setState(() {
        
          print(subCategoryLoaderList.length);
        });
      }
    });
  }


  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: FirebaseDatabase.instance.reference().child("SubCategoryNames").once(),
      builder: (context,snapshot){
        if(snapshot.hasData){
          if(snapshot.data!=null)
            {
              return DefaultTabController(
                  length: subCategoryLoaderList.length, // I made this dynamic but this is throwing an error "controller's length property does not match with number of tabs, this is because my Tab is static which is 2 how can I make it dynamic. 
                  child: Scaffold(
                    appBar: AppBar(
                      bottom: TabBar(
                        tabs: [
                          Tab(icon: Icon(Icons.looks_one), text: "List1"),  //How can i make this dynamic and text:"List1" must be the name of list items
                          Tab(icon: Icon(Icons.looks_two), text: "List2"),   
                        ],
                      ),

                    ),
                    body: TabBarView(
                      children: [
                        _buildList(key: "key1", string: "a"),
                        _buildList(key: "key2", string: "List2: "),
                      ],
                    ),
                  ));
            }else{
           return Loader();
          }
        }else{
          return Loader();
        }
      },

    );

  }

  Widget _buildList({String key, String string}) {
    return ListView.builder(
      shrinkWrap: true,
      scrollDirection: Axis.vertical,
      itemCount: subCategoryLoaderList.length,

      itemBuilder: (context, index1){
        return Container(
          child: Text(subCategoryLoaderList[index1].Name+string),
        );
      },
    );
  }
}

And I also want TabBarView to be dynamic as well, so that it will render the items accordingly.I need to fetch all the data belongs to that subcategory.


Solution

  • The number of tabs and TabBarView's children must be the same as DefaultTabController's length. one way of doing that is to have a map function that turns SubCategoryLoader into Tabs or pages:

      @override
      Widget build(BuildContext context) {
        return FutureBuilder(
          future: FirebaseDatabase.instance
              .reference()
              .child("SubCategoryNames")
              .once(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              if (snapshot.data != null) {
                return DefaultTabController(
                    length: subCategoryLoaderList.length,
                    child: Scaffold(
                      appBar: AppBar(
                        bottom: TabBar(
                          tabs: subCategoryLoaderList
                              .map((subCatagory) => Tab(text: subCatagory.Name))
                              .toList(),
                        ),
                      ),
                      body: TabBarView(
                        children: subCategoryLoaderList.map((sub){
                          return _buildList(key: "key${sub.id}", string: "some string");
                        }).toList(),
                      ),
                    ));
              } else {
                return Loader();
              }
            } else {
              return Loader();
            }
          },
        );
      }