0

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.

0 Answers0