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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 16:42:00