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

Flutter收藏功能问题:本地API与DB ID对比、点击无响应及列表展示

解决Flutter收藏功能核心问题:sqflite交互、状态同步与收藏列表展示

一、先实现sqflite数据库操作工具类

先封装一个数据库助手类,专门处理收藏ID的增删查操作(仅存ID即可,无需存储完整产品数据):

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class FavoriteDatabaseHelper {
  static final FavoriteDatabaseHelper _instance = FavoriteDatabaseHelper._internal();
  factory FavoriteDatabaseHelper() => _instance;
  FavoriteDatabaseHelper._internal();

  static Database? _database;

  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDatabase();
    return _database!;
  }

  Future<Database> _initDatabase() async {
    String path = join(await getDatabasesPath(), 'favorites.db');
    return await openDatabase(
      path,
      version: 1,
      onCreate: (db, version) async {
        await db.execute(
          'CREATE TABLE favorites(id INTEGER PRIMARY KEY)',
        );
      },
    );
  }

  // 添加收藏ID
  Future<void> addFavorite(int id) async {
    final db = await database;
    await db.insert('favorites', {'id': id}, conflictAlgorithm: ConflictAlgorithm.replace);
  }

  // 取消收藏
  Future<void> removeFavorite(int id) async {
    final db = await database;
    await db.delete('favorites', where: 'id = ?', whereArgs: [id]);
  }

  // 获取所有已收藏ID
  Future<List<int>> getFavoriteIds() async {
    final db = await database;
    final List<Map<String, dynamic>> maps = await db.query('favorites');
    return List.generate(maps.length, (i) => maps[i]['id'] as int);
  }
}

二、修复FlowersScreen的收藏逻辑与状态同步

修改_FlowersScreenState,解决按钮无响应、硬编码ID、状态不同步的问题:

class _FlowersScreenState extends State<FlowersScreen> {
  List<ListAndDetailFlowerModelResponse> _products = [];
  final FavoriteDatabaseHelper _dbHelper = FavoriteDatabaseHelper();
  List<int> _favoriteIds = [];

  @override
  void initState() {
    super.initState();
    _loadFavoriteIds(); // 初始化时加载已收藏ID
  }

  // 加载已收藏ID并同步产品状态
  Future<void> _loadFavoriteIds() async {
    _favoriteIds = await _dbHelper.getFavoriteIds();
    if (_products.isNotEmpty) {
      setState(() {
        for (var product in _products) {
          product.isFavorite = _favoriteIds.contains(product.id);
        }
      });
    }
  }

  // Code to get list flower
  Future<void> readListFlowerProduct() async {
    final String dataJsonFlower = await rootBundle
        .loadString('assets/json_file/list_and_detail_flower.json');
    final productListFlower = json.decode(dataJsonFlower);
    var listFlower = productListFlower["productFLowers"] as List<dynamic>;
    
    setState(() {
      _products = listFlower
          .map((e) => ListAndDetailFlowerModelResponse.fromJson(e))
          .toList();
      // 同步已收藏状态
      for (var product in _products) {
        product.isFavorite = _favoriteIds.contains(product.id);
      }
    });
  }
  // End Code to get list flower

  // 处理收藏/取消收藏操作
  Future<void> _toggleFavorite(ListAndDetailFlowerModelResponse product) async {
    setState(() {
      product.isFavorite = !product.isFavorite;
    });
    if (product.isFavorite) {
      await _dbHelper.addFavorite(product.id);
      _favoriteIds.add(product.id);
    } else {
      await _dbHelper.removeFavorite(product.id);
      _favoriteIds.remove(product.id);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFFCECFA),
      body: Column(
        // ... 原有布局代码不变,仅修改收藏按钮部分
        children: [
          // ... 顶部标题、按钮代码不变
          _products.isNotEmpty
              ? Expanded(
                  child: Padding(
                    padding: const EdgeInsets.only(left: 20, right: 20),
                    child: GridView.builder(
                      // ... 网格布局参数不变
                      itemBuilder: (context, index) {
                        final product = _products[index];
                        return Card(
                          // ... Card原有代码不变
                          child: Expanded(
                            child: Column(
                              // ... 图片、产品名称代码不变
                              children: [
                                // ... 图片部分不变
                                Padding(
                                  padding: const EdgeInsets.only(
                                      top: 3, bottom: 7, left: 22, right: 19),
                                  child: Row(
                                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                    children: [
                                      Text(
                                        product.flowersName,
                                        style: FlowersNameCard().text4,
                                      ),
                                      GestureDetector(
                                        // 添加点击逻辑
                                        onTap: () => _toggleFavorite(product),
                                        child: Icon(
                                          Icons.favorite,
                                          color: product.isFavorite ? Colors.red : Colors.white,
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                )
              : // ... 空状态代码不变
        ],
      ),
    );
  }
}

三、实现收藏页面展示收藏列表

创建收藏页面,从数据库获取已收藏ID,再匹配JSON中的产品数据:

class FavoritesScreen extends StatefulWidget {
  const FavoritesScreen({super.key});
  static const String routeName = '/favorites';

  @override
  State<FavoritesScreen> createState() => _FavoritesScreenState();
}

class _FavoritesScreenState extends State<FavoritesScreen> {
  final FavoriteDatabaseHelper _dbHelper = FavoriteDatabaseHelper();
  List<ListAndDetailFlowerModelResponse> _favoriteProducts = [];

  @override
  void initState() {
    super.initState();
    _loadFavoriteProducts();
  }

  Future<void> _loadFavoriteProducts() async {
    // 1. 获取已收藏ID
    final favoriteIds = await _dbHelper.getFavoriteIds();
    if (favoriteIds.isEmpty) {
      setState(() => _favoriteProducts = []);
      return;
    }
    // 2. 加载JSON产品列表
    final String dataJsonFlower = await rootBundle
        .loadString('assets/json_file/list_and_detail_flower.json');
    final productListFlower = json.decode(dataJsonFlower);
    var allProducts = productListFlower["productFLowers"] as List<dynamic>;
    var products = allProducts
        .map((e) => ListAndDetailFlowerModelResponse.fromJson(e))
        .toList();
    // 3. 筛选出已收藏的产品
    setState(() {
      _favoriteProducts = products.where((p) => favoriteIds.contains(p.id)).toList();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('我的收藏')),
      body: _favoriteProducts.isEmpty
          ? const Center(child: Text('暂无收藏'))
          : GridView.builder(
              padding: const EdgeInsets.all(20),
              gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 30,
                mainAxisSpacing: 16,
                mainAxisExtent: 160,
              ),
              itemCount: _favoriteProducts.length,
              itemBuilder: (context, index) {
                final product = _favoriteProducts[index];
                return Card(
                  color: const Color(0xFFEAC0E6),
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(10),
                  ),
                  child: Column(
                    children: [
                      Padding(
                        padding: const EdgeInsets.only(top: 13),
                        child: ClipRRect(
                          borderRadius: BorderRadius.circular(10),
                          child: Image.network(
                            product.urlImage,
                            width: 107,
                            height: 102,
                            fit: BoxFit.fill,
                          ),
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.only(
                            top: 3, bottom: 7, left: 22, right: 19),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Text(
                              product.flowersName,
                              style: FlowersNameCard().text4,
                            ),
                            GestureDetector(
                              onTap: () async {
                                await _dbHelper.removeFavorite(product.id);
                                _loadFavoriteProducts();
                              },
                              child: const Icon(Icons.favorite, color: Colors.red),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                );
              },
            ),
    );
  }
}

关键问题说明

  1. 收藏按钮无响应:原代码onTap为空,现在添加_toggleFavorite方法,同步更新本地UI状态与数据库数据。
  2. 硬编码ID问题:原代码仅固定id=1的产品状态,现在通过_favoriteIds列表对比所有产品ID,自动同步收藏状态。
  3. 收藏列表展示:通过数据库获取收藏ID后,筛选JSON中的产品数据,实现收藏页面的动态展示。

内容的提问来源于stack exchange,提问作者Ulfa Ladayya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:29:53