我有一个底部导航栏,可以在 3 页之间导航。它持续存在并保持每个页面的状态。但我希望页面在我访问时重新加载。下面是我的代码
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;
}
}
我不希望它再保持状态,但是每当我访问每个页面时,它都应该重新加载数据以显示新数据。Home、Announcement 和 Notification 从数据库中获取新数据以获取新内容,但使用上述代码,它只存储先前加载的数据,直到应用程序重新启动才获取新数据。