AutomaticKeepAliveClientMixin与Fluent UI NavigationView配合失效求助
为什么 AutomaticKeepAliveClientMixin 没生效?
Fluent UI 的 NavigationView 默认切换 PaneItem 时,会将未选中的页面组件从 Widget 树中移除销毁,而 AutomaticKeepAliveClientMixin 仅在组件仍存在于树中但处于不可见状态时才会生效,所以这种场景下Mixin起不到作用。
可行解决方案
1. 使用 IndexedStack 包裹页面
这是最直接的方案,IndexedStack 会同时渲染所有子组件并保持它们的状态,切换时只是控制显示哪个索引的页面,不会销毁其他页面。
示例代码:
class MainPage extends StatefulWidget { @override _MainPageState createState() => _MainPageState(); } class _MainPageState extends State<MainPage> { int _selectedIndex = 0; final List<Widget> _pages = [ DownloadsTab(), SettingsTab(), ]; @override Widget build(BuildContext context) { return NavigationView( pane: NavigationPane( selected: _selectedIndex, onChanged: (index) { setState(() { _selectedIndex = index; }); }, items: [ PaneItem(icon: Icon(Icons.download), title: Text('Downloads')), PaneItem(icon: Icon(Icons.settings), title: Text('Settings')), ], ), content: IndexedStack( index: _selectedIndex, children: _pages, ), ); } }
这样切换到Settings再返回Downloads时,之前加载的列表和进度都会保留。
2. 状态提升到父组件
把Downloads页面的核心状态(比如视频列表、下载进度)提取到NavigationView所在的父组件中,Downloads作为子组件接收这些状态并更新UI。
示例代码:
class MainPage extends StatefulWidget { @override _MainPageState createState() => _MainPageState(); } class _MainPageState extends State<MainPage> { int _selectedIndex = 0; List<VideoItem> _downloadList = []; Map<String, double> _progressMap = {}; void addVideo(VideoItem video) { setState(() { _downloadList.add(video); }); } void updateProgress(String videoId, double progress) { setState(() { _progressMap[videoId] = progress; }); } @override Widget build(BuildContext context) { return NavigationView( pane: NavigationPane( selected: _selectedIndex, onChanged: (index) => setState(() => _selectedIndex = index), items: [ PaneItem(icon: Icon(Icons.download), title: Text('Downloads')), PaneItem(icon: Icon(Icons.settings), title: Text('Settings')), ], ), content: _selectedIndex == 0 ? DownloadsTab( downloadList: _downloadList, progressMap: _progressMap, onAddVideo: addVideo, onUpdateProgress: updateProgress, ) : SettingsTab(), ); } } class DownloadsTab extends StatelessWidget { final List<VideoItem> downloadList; final Map<String, double> progressMap; final Function(VideoItem) onAddVideo; final Function(String, double) onUpdateProgress; const DownloadsTab({ required this.downloadList, required this.progressMap, required this.onAddVideo, required this.onUpdateProgress, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return ScaffoldPage( content: ListView.builder( itemCount: downloadList.length, itemBuilder: (context, index) { final video = downloadList[index]; final progress = progressMap[video.id] ?? 0.0; return ListTile( title: Text(video.title), subtitle: LinearProgressIndicator(value: progress), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () { final newVideo = VideoItem(id: '1', title: 'Test Video'); onAddVideo(newVideo); Future.delayed(Duration(seconds: 1), () { onUpdateProgress(newVideo.id, 0.5); }); }, child: Icon(Icons.add), ), ); } }
这种方式即使页面被销毁重建,状态也会从父组件重新获取,不会丢失。
3. 使用 PageStorage 持久化状态
如果不想用IndexedStack(担心内存占用),可以用PageStorage来保存ListView的滚动位置等基础状态,自定义数据还需结合本地存储补充。给Downloads页面的ListView设置PageStorageKey:
示例代码:
class DownloadsTab extends StatefulWidget { @override _DownloadsTabState createState() => _DownloadsTabState(); } class _DownloadsTabState extends State<DownloadsTab> with AutomaticKeepAliveClientMixin<DownloadsTab> { final List<VideoItem> _downloadList = []; final Map<String, double> _progressMap = {}; @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { super.build(context); return ScaffoldPage( content: ListView.builder( key: PageStorageKey('downloads_list'), itemCount: _downloadList.length, itemBuilder: (context, index) { final video = _downloadList[index]; final progress = _progressMap[video.id] ?? 0.0; return ListTile( title: Text(video.title), subtitle: LinearProgressIndicator(value: progress), ); }, ), ); } }
注意:此方法仅能保存组件的基础状态,自定义的下载进度、视频列表仍需通过状态提升或本地存储(如SharedPreferences、Hive)持久化。
内容的提问来源于stack exchange,提问作者pedrek
相关产品推荐
相关产品推荐

