flutter - StreamProvider 更新时如何让 Navigator 保持在活动路径上?
问题描述
在下面的代码中,我创建了一个自定义导航器,它是 StreamProvider 的子级。我的问题是每次从 Firestore 接收快照时,StreamProvider 都会重置 Navigator 路由。如何在保持当前路由的同时使用流中的新值更新 UI?
此外,第二个代码块中的 ListView 会重置流中更新的滚动位置。如何保留滚动位置,同时仍使用新值更新 UI?
class _HomeState extends State<Home> {
@override
initState() {
super.initState();
}
int _selectedIndex = 0;
Future<void> _onItemTapped(int index) async {
setState(() {
_selectedIndex = index;
print(index);
});
}
@override
Widget build(BuildContext context) {
final FixturesPage fixturesPage = new FixturesPage();
final ProfilePage profilePage = new ProfilePage();
FirebaseUser user = Provider.of<FirebaseUser>(context);
List<Widget> pages = [
fixturesPage,
profilePage,
];
return MultiProvider(
providers: [
StreamProvider<int>.value(
value: DatabaseService(userId: user.uid).totalPoints),
StreamProvider<List<Bet>>.value(
value: BettingService(userId: user.uid).getBetList)
],
child: Scaffold(
appBar: AppBar(
elevation: 0.0, backgroundColor: darkShade5, title: AppBarTitle()),
body: Container(
decoration: BoxDecoration(
color: darkShade4,
),
child: pages[_selectedIndex],
),
bottomNavigationBar: Container(
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: darkShade7,
selectedFontSize: 10,
unselectedFontSize: 10,
elevation: 0,
unselectedIconTheme:
IconThemeData(color: Colors.white.withOpacity(0.9)),
selectedIconTheme: IconThemeData(color: mainColor),
unselectedLabelStyle: navigationBarStyle.copyWith(
color: Colors.white.withOpacity(0.9)),
selectedLabelStyle: navigationBarStyle.copyWith(color: mainColor),
items: [
BottomNavigationBarItem(
icon: Container(
height: 20,
width: 20,
child: Image(
image: AssetImage("lib/images/HomeIcon.png"),
color: _selectedIndex == 0
? mainColor
: Colors.white.withOpacity(0.9),
),
),
title: SizedBox()),
BottomNavigationBarItem(
icon: Container(
height: 20,
width: 20,
child: Image(
image: AssetImage("lib/images/ProfileIcon.png"),
color: _selectedIndex == 1
? mainColor
: Colors.white.withOpacity(0.9),
),
),
title: SizedBox()),
],
currentIndex: _selectedIndex,
selectedItemColor: mainColor,
unselectedItemColor: Colors.white.withOpacity(0.3),
onTap: _onItemTapped,
),
),
),
);
}
}
class _FixturesPageState extends State<FixturesPage> {
int selectedTap = 0;
Function setSelectedTap(int tap) {
setState(() {
selectedTap = tap;
});
return null;
}
Widget selectedSport = FavoritesTap();
Function setSelectedSport(Widget newSelectedSport) {
setState(() {
selectedSport = newSelectedSport;
});
return null;
}
ScrollController listViewController =
ScrollController(keepScrollOffset: true);
@override
Widget build(BuildContext context) {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey();
List<dynamic> matches = Provider.of<List<SoccerMatch>>(context);
return Navigator(
key: navigatorKey,
initialRoute: "/",
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => Container(
color: darkShade6,
child: Column(
children: <Widget>[
//CalendarBar(),
Expanded(
child: ListView(
key: PageStorageKey('myListView'),
controller: listViewController,
children: <Widget>[
SizedBox(height: 30),
LiveSection(eventList: matches),
SizedBox(height: 20),
UpcomingSection(eventList: matches),
SizedBox(height: 20),
ResultsSection(eventList: matches)
],
),
)
],
)),
);
},
);
}
}
解决方案
显然,我通过将 ListView 与 Provider 和 ScrollController 一起移动到它自己的小部件中来解决了这两个问题:
class _FixturesPageState extends State<FixturesPage> {
int selectedTap = 0;
Function setSelectedTap(int tap) {
setState(() {
selectedTap = tap;
});
return null;
}
Widget selectedSport = FavoritesTap();
Function setSelectedSport(Widget newSelectedSport) {
setState(() {
selectedSport = newSelectedSport;
});
return null;
}
@override
Widget build(BuildContext context) {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey();
return Navigator(
key: navigatorKey,
initialRoute: "/",
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => Container(
color: darkShade6,
child: Column(
children: <Widget>[
//CalendarBar(),
Expanded(child: FixturesList())
],
)),
);
},
);
}
}
class FixturesList extends StatelessWidget {
final ScrollController listViewController =
ScrollController(keepScrollOffset: true);
@override
Widget build(BuildContext context) {
List<dynamic> matches = Provider.of<List<SoccerMatch>>(context);
return ListView(
key: PageStorageKey('myListView'),
controller: listViewController,
children: <Widget>[
SizedBox(height: 30),
LiveSection(eventList: matches),
SizedBox(height: 20),
UpcomingSection(eventList: matches),
SizedBox(height: 20),
ResultsSection(eventList: matches)
],
);
}
}
推荐阅读
- python - 如何将记录从一张表转移到另一张表?
- database - 在 LibreOffice 中,如何仅使用 Basic 连接到 Oracle 数据库
- autohotkey - AutoHotkey - 如何使用 AltGr 映射组合以将组合 Ctrl+键发送到特定应用程序?
- flutter - 通过在颤振中从另一个列表中引用来过滤列表
- .net-core - 当我添加相关实体时,实体状态被修改未添加
- r - 如何旋转 tf$keras$preprocessing$image$apply_affine_transform 的边界框
- javascript - 非导出函数的 Mocha 单元测试返回“xx 不是函数”
- arrays - Sending a concatenated bytearray
- python - 当所有方法都返回 NotImplemented 时,为什么 == 不引发“不支持 TypeError”?
- django - Redis 服务器未在 Windows 10 上启动