Flutter实现页面内与选择页同步生效的本地收藏功能咨询
Flutter本地收藏功能实现方案
核心实现思路
不用复杂状态管理框架也能实现需求,推荐用ValueNotifier + shared_preferences的轻量组合,完全满足状态同步、本地持久化的要求:
- 定义统一的收藏页面数据模型,存储页面唯一ID、名称、跳转路径等核心字段
- 封装全局单例的收藏管理类,统一处理本地存储读写、收藏状态增删逻辑
- 用
ValueListenableBuilder监听全局收藏状态,页面收藏按钮、选择页收藏列表自动同步刷新,无需手动调用setState
具体代码实现示例
1. 添加依赖
在pubspec.yaml中引入对应版本库:
dependencies: flutter: sdk: flutter shared_preferences: ^2.0.7
2. 封装收藏管理工具类
import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; // 收藏页面数据模型 class CollectionPage { final String pageId; // 页面唯一标识,不可重复 final String pageName; // 页面显示名称 final String routePath; // 页面跳转路由 CollectionPage({ required this.pageId, required this.pageName, required this.routePath, }); Map<String, dynamic> toJson() => { 'pageId': pageId, 'pageName': pageName, 'routePath': routePath, }; factory CollectionPage.fromJson(Map<String, dynamic> json) => CollectionPage( pageId: json['pageId'], pageName: json['pageName'], routePath: json['routePath'], ); } // 全局收藏管理单例 class CollectionManager { static final CollectionManager _instance = CollectionManager._internal(); factory CollectionManager() => _instance; CollectionManager._internal(); // 收藏状态监听,变化后自动通知所有监听的组件 final ValueNotifier<List<CollectionPage>> collectionList = ValueNotifier([]); static const String _storageKey = 'user_page_collections'; // App启动时调用一次,初始化本地收藏数据 Future<void> init() async { final prefs = await SharedPreferences.getInstance(); final String? dataStr = prefs.getString(_storageKey); if (dataStr != null) { final List<dynamic> jsonList = jsonDecode(dataStr); collectionList.value = jsonList.map((e) => CollectionPage.fromJson(e)).toList(); } } // 切换页面收藏状态 Future<void> toggleCollect(CollectionPage page) async { final prefs = await SharedPreferences.getInstance(); final List<CollectionPage> currentList = List.from(collectionList.value); final targetIndex = currentList.indexWhere((item) => item.pageId == page.pageId); if (targetIndex >= 0) { currentList.removeAt(targetIndex); } else { currentList.add(page); } // 同步更新状态和本地存储 collectionList.value = currentList; await prefs.setString(_storageKey, jsonEncode(currentList.map((e) => e.toJson()).toList())); } // 判断单个页面是否已收藏 bool isCollected(String pageId) { return collectionList.value.any((item) => item.pageId == pageId); } }
3. 页面内收藏按钮调用示例
// 提前实例化收藏管理工具 final collectionManager = CollectionManager(); // 收藏按钮组件 ValueListenableBuilder<List<CollectionPage>>( valueListenable: collectionManager.collectionList, builder: (context, list, child) { bool collected = collectionManager.isCollected('当前页面的唯一ID'); return IconButton( icon: Icon( collected ? Icons.favorite : Icons.favorite_border, color: collected ? Colors.red : Colors.grey, ), onPressed: () { collectionManager.toggleCollect(CollectionPage( pageId: '当前页面的唯一ID', pageName: '当前页面显示名称', routePath: '/当前页面路由地址', )); }, ); }, )
4. 页面选择窗口展示收藏列表示例
ValueListenableBuilder<List<CollectionPage>>( valueListenable: collectionManager.collectionList, builder: (context, list, child) { if (list.isEmpty) return const Text('暂无收藏页面'); return ListView.builder( shrinkWrap: true, itemCount: list.length, itemBuilder: (context, index) { final page = list[index]; return ListTile( title: Text(page.pageName), onTap: () => Navigator.pushNamed(context, page.routePath), ); }, ); }, )
5. App启动初始化
在main函数中完成初始化:
void main() async { WidgetsFlutterBinding.ensureInitialized(); // 初始化收藏管理工具 await CollectionManager().init(); runApp(const MyApp()); }
开发建议
- 页面唯一ID建议直接用路由路径,避免重复导致收藏逻辑出错
- 如果后续需要支持更多收藏类型,可以扩展
CollectionPage的type字段做区分 - 所有收藏相关的读写操作都通过
CollectionManager处理,不要在业务页面单独读写shared_preferences,避免状态不一致 - 如果后续收藏数据量超过千条,可以替换为Hive、Isar等轻量本地数据库,性能更优,用法和当前方案差异不大
内容的提问来源于stack exchange,提问作者eno2
相关产品推荐
相关产品推荐

