1

I have a bottomnavigation bar that navigates between 3 pages. It persists and keeps the state of each page. But I want the page to reload whenever I visit. Below is my code


class navigationPurchase extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => AppState();
}

class AppState extends State<navigationPurchase> {
  // this is static property so other widget throughout the app
  // can access it simply by AppState.currentTab
  static int currentTab = 0;

  // list tabs here
  final List<TabItem> tabs = [
    TabItem(
      tabName: "Home",
      icon: Icons.home,
      page: HomepagePurchase(),
    ),
    TabItem(
      tabName: "Announcement",
      icon: Icons.announcement,
      page: MyAnnouncementAppPurchase(),
    ),
    TabItem(
      tabName: "Notification",
      icon: Icons.notifications,
      page: MyNotificationAppPurchase(),
    ),
  ];

  AppState() {
    // indexing is necessary for proper funcationality
    // of determining which tab is active
    tabs.asMap().forEach((index, details) {
      details.setIndex(index);
    });
  }

  // sets current tab index
  // and update state
  void _selectTab(int index) {
    if (index == currentTab) {
      // pop to first route
      // if the user taps on the active tab
      tabs[index].key.currentState.popUntil((route) => route.isFirst);
    } else {
      // update the state
      // in order to repaint
      setState(() => currentTab = index);
    }
  }

  @override
  Widget build(BuildContext context) {
    // WillPopScope handle android back btn
    return WillPopScope(
      onWillPop: () async {
        final isFirstRouteInCurrentTab =
        !await tabs[currentTab].key.currentState.maybePop();
        if (isFirstRouteInCurrentTab) {
          // if not on the 'main' tab
          if (currentTab != 0) {
            // select 'main' tab
            _selectTab(0);
            // back button handled by app
            return false;
          }
        }
        // let system handle back button if we're on the first route
        return isFirstRouteInCurrentTab;
      },
      // this is the base scaffold
      // don't put appbar in here otherwise you might end up
      // with multiple appbars on one screen
      // eventually breaking the app
      child: Scaffold(
        // indexed stack shows only one child
        body: IndexedStack(
          index: currentTab,
          children: tabs.map((e) => e.page).toList(),
        ),
        // Bottom navigation
        bottomNavigationBar: BottomNavigation(
          onSelectTab: _selectTab,
          tabs: tabs,
        ),
      ),
    );
  }
}

class TabItem {
  // you can customize what kind of information is needed
  // for each tab
  final String tabName;
  final IconData icon;
  final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>();
  int _index = 0;
  Widget _page;

  TabItem({
    @required this.tabName,
    @required this.icon,
    @required Widget page,
  }) {
    _page = page;
  }

  // I was getting a weird warning when using getters and setters for _index
  // so I converted them to functions

  // used to set the index of this tab
  // which will be used in identifying if this tab is active
  void setIndex(int i) {
    _index = i;
  }

  int getIndex() => _index;

// adds a wrapper around the page widgets for visibility
// visibility widget removes unnecessary problems
// like interactivity and animations when the page is inactive
  Widget get page {
    return Visibility(
      // only paint this page when currentTab is active
      visible: _index == AppState.currentTab,
      // important to preserve state while switching between tabs
      maintainState: true,
      child: Navigator(
        // key tracks state changes
        key: key,
        onGenerateRoute: (routeSettings) {
          return MaterialPageRoute(
            builder: (_) => _page,
          );
        },
      ),
    );
  }
}

class BottomNavigation extends StatelessWidget {
  BottomNavigation({
    this.onSelectTab,
    this.tabs,
  });

  final ValueChanged<int> onSelectTab;
  final List<TabItem> tabs;

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      items: tabs
          .map(
            (e) => _buildItem(
          index: e.getIndex(),
          icon: e.icon,
          tabName: e.tabName,
        ),
      )
          .toList(),
      onTap: (index) => onSelectTab(
        index,
      ),
    );
  }

  BottomNavigationBarItem _buildItem(
      {int index, IconData icon, String tabName}) {
    return BottomNavigationBarItem(
      icon: Icon(
        icon,
        color: _tabColor(index: index),
      ),
      // ignore: deprecated_member_use
      title: Text(
        tabName,
        style: TextStyle(
          color: _tabColor(index: index),
          fontSize: 12,
        ),
      ),
    );
  }

  Color _tabColor({int index}) {
    return AppState.currentTab == index ? Colors.blue : Colors.grey;
  }
}


I don't want it to keep state anymore but whenever I visit each of the pages it should reload the data to display new data. Home, Announcement, and Notification get new data from the database for new content but with the above code, it only stores the previous data loaded and not get new one until the application is restarted.

mideveloper
  • 327
  • 1
  • 7
  • 21

4 Answers4

1

Do not use indexedStack, just use list.

broheat
  • 147
  • 8
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 15 '22 at 06:49
0

By default, every page is reload / rebuild each time you tap on different page.

Rudy Rudy
  • 125
  • 1
  • 6
0

Option 1: indexed stack.

Here is an example from one of my projs. But tbh its not the best way and i ended up not using it.

IndexedStack(
              index: selectedIndex,
                 children: <Widget>[
                   Navigator(
                     key: reminderScreen,
                     onGenerateRoute: (route) => MaterialPageRoute(
                       settings: route,
                       builder: (context) => ReminderPage(),
                    ),
                   ),
                  Navigator(
                     key: doneScreen,
                     onGenerateRoute: (route) => MaterialPageRoute(
                       settings: route,
                      builder: (context) => DonePage(),
                     ),
                   ),
                   Navigator(
                    key: historyScreen,
                     onGenerateRoute: (route) => MaterialPageRoute(
                       settings: route,
                       builder: (context) => HistoryPage(),
                     ),
                  ),
                 ],
               ),
the other way is: to set a global key

like this:

class _ReminderPageState extends State<ReminderPage> {
  final _reminderDetailsKey = GlobalKey<FormState>();

and later put it in a form:

child: Form(
          key: _reminderDetailsKey, //this is the global key
          child: Column(...//your pages
MNBWorld
  • 529
  • 1
  • 5
  • 25
-1

List _pages = [Dashboard(), Medicine(),Contact(),Account()]

   Scaffold(
            body: _pages[tabIndex],// this will reload the screen when tap
            bottomNavigationBar:BottomNavigationBar(
      unselectedItemColor: Colors.white.withOpacity(0.6),
      selectedItemColor: Colors.white,
      backgroundColor: kPrimaryColor,
      currentIndex: tabIndex,
      onTap: changeTabIndex(),
      type: BottomNavigationBarType.fixed,
      items: const [
        BottomNavigationBarItem(
          label: "Dashboard",
          icon: Icon(Icons.dashboard),
        ),
        BottomNavigationBarItem(
          label: "Medicine",
          icon: Icon(Icons.medication),
        ),
        BottomNavigationBarItem(
          label: "Contact",
          icon: Icon(Icons.chat),
        ),
        BottomNavigationBarItem(
          label: "Account",
          icon: Icon(Icons.account_box),
        ),
      ],
    )
                
          )
Abhinav
  • 36
  • 1
  • 5
  • this is not what he asked for – MNBWorld Nov 10 '22 at 15:27
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 10 '22 at 15:27
  • The code above does what he asked for. It will rebuild the page when clicked on ! Please check before voting and don't misguide!@MNBWorld – Abhinav Nov 17 '22 at 08:44