Can not properly loop through the fetched firestore data in flutter and display it in Tabs

Issue

I am trying to loop through the fetched data using StreamBuilder and push it to the TabController.

The problem is that in a TabController I need to set the length property. In my case it will be 3, but ideally it should be counted dynamically based on amount of documents in my collection.

And then in my TapBar I have tabs property, which should look like something like this:

 final List<Widget> myTabs = [
    Tab(text: 'Tab 1'),
    Tab(text: 'Tab 2'),
    Tab(text: 'Tab 3'),
  ];

So I am trying to generate that myTabs list in a StreamBuilder:

final List<Widget> finalTabs = [];
Timestamp eventTabControl = snapshot.data?.docs[index].data()['day'];
finalTabs.addAll([Tab(text: eventTabControl.toDate().toString())]);

but it does not work as I expect. It just generates 1 tab for me instead of 3.

enter image description here

expected result is:

enter image description here

However when I try to print finalTabs in console it displays me all my 3 values.

My whole code is:

import 'package:book_club/config/palette.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

class EventTabControl extends StatefulWidget {
  const EventTabControl({Key? key}) : super(key: key);

  @override
  State<EventTabControl> createState() => _EventTabControlState();
}

class _EventTabControlState extends State<EventTabControl>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

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

  _handleTabSelection() {
    if (_tabController.indexIsChanging) {
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: FirebaseFirestore.instance.collection("schedule").snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return Center(
            child: CircularProgressIndicator(),
          );
        } else {
          return ListView.builder(
              shrinkWrap: true,
              physics: NeverScrollableScrollPhysics(),
              itemCount: snapshot.data?.docs.length,
              itemBuilder: (_, index) {
                final List<Widget> finalTabs = [];
                Timestamp eventTabControl =
                    snapshot.data?.docs[index].data()['day'];
                finalTabs
                    .addAll([Tab(text: eventTabControl.toDate().toString())]);
                return Container(
                  child: Container(
                   
                    child: TabBar(
                      controller: _tabController,
                      indicatorWeight: 2.5,
                      indicatorSize: TabBarIndicatorSize.tab,
                      labelColor: Palette.custGreen,
                      unselectedLabelColor: Palette.custBlue,
                      indicator: BoxDecoration(
                        border: Border(
                          bottom: BorderSide(
                            color: Palette.custGreen,
                            width: 2.0,
                          ),
                        ),
                      ),
                      tabs: finalTabs,
                    ),
                  ),
                );
              });
        }
      },
    );
  }
}

This is just a logic for TabController.

Solution

You are using ListView Builder which is not suitable as it will render your widgets 3 times individually based on your condition ,instead, you could return tabs dynamically,

Your else part:

 else {   final List<Widget> finalTabs = [];
            snapshot.data?.docs.forEach((document){
            Timestamp eventTabControl = document.data()['day'];
               finalTabs.add(eventTabControl.toDate().toString());
              }
          );

          return  Container(
                   
                    child: TabBar(
                      controller: _tabController,
                      indicatorWeight: 2.5,
                      indicatorSize: TabBarIndicatorSize.tab,
                      labelColor: Palette.custGreen,
                      unselectedLabelColor: Palette.custBlue,
                      indicator: BoxDecoration(
                        border: Border(
                          bottom: BorderSide(
                            color: Palette.custGreen,
                            width: 2.0,
                          ),
                        ),
                      ),
                      tabs: finalTabs.isEmpty
                      ? <Widget>[]
                      : finalTabs.map((dynamicContent) {
                          return new Text('your contentContent')),
                       );
                      }).toList(),
                    ),
                 
                );
              
        }

Answered By – Krish Bhanushali

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published