I have a BottomNavigationBar and realized that when I was changing the index I was displaying pretty much the exact same page/widget except for a 2 parameters. So I decided to consolidate the widgets into one that take in the parameters, but the issue is that now that I did that it doesn't work. I assume it has something to do with the page already being initialized and having a state? Here is what my widget with the BottomNavigationBar looks like:
class SpeedPage extends StatefulWidget {
const SpeedPage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return _SpeedPageState();
}
}
class _SpeedPageState extends State<SpeedPage> {
int _currentIndex = 0;
static const List<Widget> _widgetOptions = <Widget>[
WorkoutListPage(categoryIndex: 0, subCategories: Utils.srsDropdown),
WorkoutListPage(categoryIndex: 1, subCategories: Utils.ddsDropdown),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [_widgetOptions.elementAt(_currentIndex)],
)),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.looks_one_outlined),
label: 'Single rope',
backgroundColor: Color.fromRGBO(204, 16, 138, 1)),
BottomNavigationBarItem(
icon: Icon(Icons.looks_two_outlined),
label: 'Double dutch',
backgroundColor: Color.fromRGBO(204, 16, 138, 1)),
],
onTap: _onItemTapped,
),
);
}
void _onItemTapped(int index) {
setState(() {
_currentIndex = index;
});
}
}
and here is what my WorkoutListPage widget looks like:
class WorkoutListPage extends StatefulWidget {
final int categoryIndex;
final List<String> subCategories;
const WorkoutListPage(
{Key? key, required this.categoryIndex, required this.subCategories})
: super(key: key);
@override
State<StatefulWidget> createState() {
return _WorkoutListPageState();
}
}
class _WorkoutListPageState extends State<WorkoutListPage> {
bool isLoading = true;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) =>
FutureBuilder<List<Map<String, dynamic>>>(
future: MyCard.getData(widget.categoryIndex, widget.subCategories)!
.whenComplete(() => setState(() {
isLoading = false;
})),
builder: ((context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return FutureBuilder<List<MyCard>>(
future: MyCard.readData(snapshot.data),
builder: (context, cards) {
if (cards.hasData) {
final card = cards.data!;
return Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
return MyCard.buildCard(card[index], context);
},
),
);
} else {
return const Text("No data");
}
});
} else {
return isLoading
? Column(
children: const [CircularProgressIndicator()],
)
: const Text("You do not have any workouts yet");
}
}),
);
}
and this doesn't work – it lags between tabs or the page simply doesn't change. Ironically, if in my SpeedPage I change my _widgetOptions to be the following:
static const List<Widget> _widgetOptions = <Widget>[
SpeedSRPage(),
SpeedDDPage()
];
where my SpeedSRPage() and SpeedDDPage() are:
class SpeedSRPage extends StatefulWidget {
const SpeedSRPage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return _SpeedSRPageState();
}
}
class _SpeedSRPageState extends State<SpeedSRPage> {
var isLoading = true;
@override
Widget build(BuildContext context) =>
FutureBuilder<List<Map<String, dynamic>>>(
future: MyCard.getData(0, Utils.srsDropdown)!
.whenComplete(() => setState(() {
isLoading = false;
})),
builder: ((context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return FutureBuilder<List<MyCard>>(
future: MyCard.readData(snapshot.data),
builder: (context, cards) {
if (cards.hasData) {
final card = cards.data!;
return Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
return MyCard.buildCard(card[index], context);
},
),
);
} else {
return const Text("No data");
}
});
} else {
return isLoading
? Column(
children: const [CircularProgressIndicator()],
)
: const Text("You do not have any workouts yet");
}
}),
);
}
and
class SpeedDDPage extends StatefulWidget {
const SpeedDDPage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return _SpeedDDPageState();
}
}
class _SpeedDDPageState extends State<SpeedDDPage> {
var isLoading = true;
@override
Widget build(BuildContext context) =>
FutureBuilder<List<Map<String, dynamic>>>(
future: MyCard.getData(1, Utils.ddsDropdown)!
.whenComplete(() => setState(() {
isLoading = false;
})),
builder: ((context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return FutureBuilder<List<MyCard>>(
future: MyCard.readData(snapshot.data),
builder: (context, cards) {
if (cards.hasData) {
final card = cards.data!;
return Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
return MyCard.buildCard(card[index], context);
},
),
);
} else {
return const Text("No data");
}
});
} else {
return isLoading
? Column(
children: const [CircularProgressIndicator()],
)
: const Text("You do not have any workouts yet");
}
}),
);
}
respectively, it works. I also know that it isn't a problem with the WorkoutListPage because if I change my _widgetOptions to something like:
static const List<Widget> _widgetOptions = <Widget>[
WorkoutListPage(categoryIndex: 0, subCategories: Utils.srsDropdown),
SpeedDDPage(),
];
it also works. So the issue seems to be that I am using the same widget (WorkoutListPage) twice in one BottomNavigationBar. I suspect it has something to do with the state initiation; if I add this line to the workoutListPageState():
void initState() {
print("Initiated state");
super.initState();
}
"Initiated state" only prints once if I switch tabs and the items in my _widgetOptions are both a WorkoutListPage. But if I switch my _widgetOptions to have different widgets "Initiated state" prints out every time I change tabs.