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.