Flutter实现书签收藏功能并使用shared_preferences本地存储问题咨询
实现步骤
1. 引入依赖
在pubspec.yaml中添加shared_preferences依赖:
dependencies: flutter: sdk: flutter shared_preferences: ^2.0.7
执行flutter pub get完成安装。
2. 封装收藏本地操作工具类
统一处理收藏数据的增删查操作:
import 'package:shared_preferences/shared_preferences.dart'; class FavoritesUtil { // 本地存储的key值 static const String _favoritesKey = 'favorite_item_ids'; // 获取所有已收藏的内容唯一ID static Future<List<String>> getFavorites() async { final prefs = await SharedPreferences.getInstance(); return prefs.getStringList(_favoritesKey) ?? []; } // 新增收藏 static Future<void> addFavorite(String itemId) async { final prefs = await SharedPreferences.getInstance(); List<String> favorites = await getFavorites(); if (!favorites.contains(itemId)) { favorites.add(itemId); await prefs.setStringList(_favoritesKey, favorites); } } // 移除收藏 static Future<void> removeFavorite(String itemId) async { final prefs = await SharedPreferences.getInstance(); List<String> favorites = await getFavorites(); if (favorites.contains(itemId)) { favorites.remove(itemId); await prefs.setStringList(_favoritesKey, favorites); } } // 判断单条内容是否已收藏 static Future<bool> isItemFavorited(String itemId) async { List<String> favorites = await getFavorites(); return favorites.contains(itemId); } }
注意:所有可收藏内容必须配置唯一的
itemId,不可重复,你可以根据自身业务场景替换为实际的资源唯一标识。
3. 修改详情页收藏按钮逻辑
将详情页改为StatefulWidget,进入页面时读取收藏状态,点击时切换状态并同步本地存储:
class DetailPage extends StatefulWidget { // 从选择页传入当前内容的唯一ID final String itemId; const DetailPage({super.key, required this.itemId}); @override State<DetailPage> createState() => _DetailPageState(); } class _DetailPageState extends State<DetailPage> { bool isFavorited = false; @override void initState() { super.initState(); // 进入页面先加载当前内容的收藏状态 _loadFavStatus(); } _loadFavStatus() async { bool status = await FavoritesUtil.isItemFavorited(widget.itemId); setState(() { isFavorited = status; }); } // 切换收藏状态 _toggleFav() async { if (isFavorited) { await FavoritesUtil.removeFavorite(widget.itemId); } else { await FavoritesUtil.addFavorite(widget.itemId); } setState(() { isFavorited = !isFavorited; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( actions: <Widget>[ IconButton( onPressed: _toggleFav, icon: isFavorited ? Icon(Icons.bookmark_rounded, color: Colors.yellow[800], size: 30) : Icon(Icons.bookmark_add_outlined, color: Colors.yellow[800],size: 30), ), ], ), // 剩余页面内容 ); } }
4. 修改LearnLevelButton组件
新增isFavorited参数,根据收藏状态切换边框颜色:
class LearnLevelButton extends StatelessWidget { LearnLevelButton({ Key ?key, this.text = '', this.width = 80.0, this.height = 80.0, this.borderRadius = 50.0, required this.onTap, // 新增是否收藏参数,默认未收藏 this.isFavorited = false, }) : super(key: key); final String text; final VoidCallback onTap; final double width; final double height; final double borderRadius; final bool isFavorited; @override Widget build(BuildContext context) { var gradient = const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xff7ba6f9), Color(0xff7ba6f9), ], ); return InkWell( onTap: onTap, child: Center( child: Padding( padding: const EdgeInsets.only( top: 20.0, bottom: 20.0, left: 22.0, right: 22.0, ), child: Container( padding: const EdgeInsets.all(3.0), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(borderRadius), // 外层边框根据收藏状态变色 border: Border.all( width: 0.3, color: isFavorited ? Colors.yellow[800]! : Colors.black38, ), boxShadow: const [ BoxShadow( blurRadius: 10.0, offset: Offset(5.0, 5.0), color: Color.fromRGBO(0, 0, 0, 0.3), ), ], gradient: gradient, ), width: width, height: height, child: Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(borderRadius), // 内层边框同步变色,不需要可以保留原有值 border: Border.all( width: 0.3, color: isFavorited ? Colors.yellow[800]! : Colors.black26, ), boxShadow: const [ BoxShadow( blurRadius: 1.0, offset: Offset(1.0, 1.5), color: Color.fromRGBO(0, 0, 0, 0.3), ), ], gradient: gradient, ), child: Center( child: Text( text, style: const TextStyle( color: Colors.white, fontSize: 20.0, fontWeight: FontWeight.bold, ), ), ), ), ), ), ), ); } }
5. 修改选择页逻辑
进入页面时加载所有收藏ID,从详情页返回时刷新状态:
class LevelSelectPage extends StatefulWidget { const LevelSelectPage({super.key}); @override State<LevelSelectPage> createState() => _LevelSelectPageState(); } class _LevelSelectPageState extends State<LevelSelectPage> { List<String> allFavorites = []; @override void initState() { super.initState(); _loadAllFavorites(); } // 加载所有已收藏的ID _loadAllFavorites() async { List<String> favs = await FavoritesUtil.getFavorites(); setState(() { allFavorites = favs; }); } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ // 示例按钮1,对应唯一ID level_1 LearnLevelButton( text: 'Level 1', isFavorited: allFavorites.contains('level_1'), onTap: () async { // 跳转详情页传入对应ID await Navigator.push(context, MaterialPageRoute(builder: (context)=> DetailPage(itemId: 'level_1'))); // 从详情页返回后刷新收藏状态 _loadAllFavorites(); }, ), // 示例按钮2,对应唯一ID level_2 LearnLevelButton( text: 'Level 2', isFavorited: allFavorites.contains('level_2'), onTap: () async { await Navigator.push(context, MaterialPageRoute(builder: (context)=> DetailPage(itemId: 'level_2'))); _loadAllFavorites(); }, ), // 其余按钮按上述规则添加即可 ], ), ); } }
内容的提问来源于stack exchange,提问作者eno2
相关产品推荐
相关产品推荐

