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.
expected result is:
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.
CodePudding user response:
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(),
),
);
}