You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 00:06:03