鸿蒙+Flutter 跨平台开发——物品过期追踪器开发实战

🚀运行效果展示

在这里插入图片描述
在这里插入图片描述

📝 前言

在快节奏的现代生活中,我们经常会遇到物品过期的问题——冰箱里的食品过期变质、药箱里的药品超过保质期、化妆品使用期限已过等。这些问题不仅造成了资源浪费,还可能对健康产生潜在威胁。为了解决这个痛点,我们决定开发一款物品过期追踪器,帮助用户高效管理家中物品的保质期。

本项目采用鸿蒙+Flutter的跨平台开发技术栈,实现了一套完整的物品过期管理系统。通过本项目,我们将深入探讨如何在鸿蒙平台上使用Flutter框架进行应用开发,包括数据模型设计、本地数据库存储、响应式UI设计等核心技术点。

🔧 技术栈

技术 版本 用途
Flutter 3.6.2 跨平台UI框架
Dart 3.6.2 开发语言
SQLite 2.3.3 本地数据库
Path Provider 2.1.4 文件路径管理
HuaWei HarmonyOS 3.0+ 目标平台

📱 应用介绍

🌟 应用功能

物品过期追踪器是一款专注于帮助用户管理物品保质期的应用,主要功能包括:

  • 物品管理:添加、编辑、删除物品信息
  • 状态自动分类:根据过期日期自动分类为正常、即将过期、已过期
  • 多维度筛选:支持按状态、类型筛选物品
  • 直观的数据统计:展示物品总数、即将过期数、已过期数
  • 清晰的视觉反馈:不同状态使用不同颜色标识
  • 响应式设计:适配不同屏幕尺寸

🎯 应用价值

  • 减少浪费:及时提醒用户使用即将过期的物品
  • 保障健康:避免使用过期食品、药品和化妆品
  • 提高生活效率:快速了解家中物品的保质期情况
  • 环保节能:减少过期物品对环境的污染

🏗️ 核心功能实现

1. 系统架构设计

本项目采用分层架构设计,确保代码的可维护性和可扩展性:

UI层

服务层

仓库层

数据库层

SQLite数据库

  • UI层:负责用户界面展示和交互
  • 服务层:处理业务逻辑
  • 仓库层:封装数据访问逻辑
  • 数据库层:负责与SQLite数据库交互

2. 数据模型设计

2.1 物品类型枚举
/// 物品类型枚举
enum ItemType {
  /// 食品
  food,
  /// 药品
  medicine,
  /// 化妆品
  cosmetic,
  /// 其他物品
  other,
}
2.2 物品状态枚举
/// 物品状态枚举
enum ItemStatus {
  /// 正常(未过期)
  normal,
  /// 即将过期(7天内)
  soonExpire,
  /// 已过期
  expired,
}
2.3 物品模型
/// 物品模型
class Item {
  /// 物品ID
  final String id;
  /// 物品名称
  final String name;
  /// 物品类型
  final ItemType type;
  /// 购买日期
  final DateTime purchaseDate;
  /// 过期日期
  final DateTime expiryDate;
  /// 物品描述
  final String? description;
  /// 物品数量
  final int quantity;
  /// 是否开启提醒
  final bool enableReminder;
  /// 创建时间
  final DateTime createdAt;
  /// 更新时间
  final DateTime updatedAt;
  
  // 构造函数、toJson、fromJson等方法...
  
  /// 获取物品状态
  ItemStatus get status {
    final now = DateTime.now();
    final daysUntilExpiry = expiryDate.difference(now).inDays;
    
    if (daysUntilExpiry < 0) {
      return ItemStatus.expired;
    } else if (daysUntilExpiry <= 7) {
      return ItemStatus.soonExpire;
    } else {
      return ItemStatus.normal;
    }
  }
}

3. 数据库设计

3.1 数据库表结构
字段名 数据类型 约束 描述
id TEXT PRIMARY KEY 物品ID
name TEXT NOT NULL 物品名称
type INTEGER NOT NULL 物品类型(枚举值)
purchaseDate TEXT NOT NULL 购买日期
expiryDate TEXT NOT NULL 过期日期
description TEXT 物品描述
quantity INTEGER NOT NULL DEFAULT 1 物品数量
enableReminder INTEGER NOT NULL DEFAULT 1 是否开启提醒(1:是, 0:否)
createdAt TEXT NOT NULL 创建时间
updatedAt TEXT NOT NULL 更新时间
3.2 数据库操作封装
/// 数据库助手类
class DatabaseHelper {
  /// 单例实例
  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
  
  /// 数据库实例
  static Database? _database;
  
  /// 获取数据库实例(懒加载)
  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDatabase();
    return _database!;
  }
  
  /// 初始化数据库
  Future<Database> _initDatabase() async {
    Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, 'expiry_tracker.db');
    
    return await openDatabase(
      path,
      version: databaseVersion,
      onCreate: _onCreate,
      onUpgrade: _onUpgrade,
    );
  }
  
  /// 其他CRUD操作方法...
}

4. UI设计与实现

4.1 主界面布局

主界面采用卡片式布局,包含三个主要部分:

  1. 统计卡片:展示物品总数、即将过期数、已过期数
  2. 筛选标签:支持按状态筛选物品
  3. 物品列表:以卡片形式展示物品信息
class MainScreen extends StatefulWidget {
  const MainScreen({super.key});
  
  
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  // 状态管理和业务逻辑...
  
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('过期物品追踪器'),
        backgroundColor: Colors.blue,
        centerTitle: true,
      ),
      body: SafeArea(
        child: Container(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // 统计卡片
              Row(
                children: [
                  Expanded(child: _buildStatCard('全部物品', _totalCount, Colors.blue)),
                  const SizedBox(width: 12),
                  Expanded(child: _buildStatCard('即将过期', _soonExpiredCount, Colors.orange)),
                  const SizedBox(width: 12),
                  Expanded(child: _buildStatCard('已过期', _expiredCount, Colors.red)),
                ],
              ),
              
              // 筛选标签
              Padding(
                padding: const EdgeInsets.only(top: 16, bottom: 12),
                child: Row(
                  children: [
                    FilterChip(
                      label: const Text('全部'),
                      selected: _filterStatus == null,
                      onSelected: (selected) => _filterItems(selected ? null : _filterStatus),
                      selectedColor: Colors.blue,
                    ),
                    // 其他筛选标签...
                  ],
                ),
              ),
              
              // 物品列表
              Expanded(
                child: _filteredItems.isEmpty
                    ? Center(/* 空状态UI */)
                    : ListView.builder(
                        itemCount: _filteredItems.length,
                        itemBuilder: (context, index) {
                          final item = _filteredItems[index];
                          return _buildItemCard(item);
                        },
                      ),
              ),
            ],
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _navigateToAddItem,
        backgroundColor: Colors.blue,
        child: const Icon(Icons.add),
      ),
    );
  }
  
  // 其他辅助方法...
}
4.2 物品卡片设计

物品卡片采用清晰的信息层级设计,包含物品名称、状态标签、类型、日期信息等:

Widget _buildItemCard(Item item) {
  return Card(
    elevation: 2,
    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
    margin: const EdgeInsets.only(bottom: 12),
    child: Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 物品名称和状态
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Expanded(
                child: Text(
                  item.name,
                  style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                ),
              ),
              Container(
                padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                decoration: BoxDecoration(
                  color: _itemService.getItemStatusColor(item.status).withOpacity(0.2),
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Text(
                  _itemService.getItemStatusName(item.status),
                  style: TextStyle(
                    fontSize: 12,
                    color: _itemService.getItemStatusColor(item.status),
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
            ],
          ),
          // 其他物品信息...
        ],
      ),
    ),
  );
}
4.3 添加物品页面

添加物品页面采用表单布局,包含物品名称、类型、日期选择、数量等字段:

class AddItemScreen extends StatefulWidget {
  const AddItemScreen({super.key});
  
  
  State<AddItemScreen> createState() => _AddItemScreenState();
}

class _AddItemScreenState extends State<AddItemScreen> {
  // 表单控制器和状态管理...
  
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('添加物品'),
        backgroundColor: Colors.blue,
        centerTitle: true,
      ),
      body: SafeArea(
        child: Container(
          padding: const EdgeInsets.all(16),
          child: Form(
            key: _formKey,
            child: ListView(
              children: [
                // 物品名称输入框
                TextFormField(
                  controller: _nameController,
                  decoration: const InputDecoration(
                    labelText: '物品名称',
                    border: OutlineInputBorder(),
                    prefixIcon: Icon(Icons.inventory),
                  ),
                  validator: (value) {
                    if (value == null || value.isEmpty) {
                      return '请输入物品名称';
                    }
                    return null;
                  },
                ),
                // 其他表单字段...
                
                // 提交按钮
                ElevatedButton(
                  onPressed: _isSubmitting ? null : _submitForm,
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.blue,
                    foregroundColor: Colors.white,
                    padding: const EdgeInsets.symmetric(vertical: 16),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                  ),
                  child: _isSubmitting
                      ? const CircularProgressIndicator(color: Colors.white)
                      : const Text(
                          '添加物品',
                          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                        ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
  
  // 其他辅助方法...
}

5. 核心业务逻辑

5.1 物品状态自动计算

根据物品的过期日期和当前日期,自动计算物品状态:

ItemStatus get status {
  final now = DateTime.now();
  final daysUntilExpiry = expiryDate.difference(now).inDays;
  
  if (daysUntilExpiry < 0) {
    return ItemStatus.expired;
  } else if (daysUntilExpiry <= 7) {
    return ItemStatus.soonExpire;
  } else {
    return ItemStatus.normal;
  }
}
5.2 数据类型转换

处理SQLite不支持布尔类型的问题:

/// 转换为JSON
Map<String, dynamic> toJson() {
  return {
    // 其他字段...
    'enableReminder': enableReminder ? 1 : 0,
    // 其他字段...
  };
}

/// 从JSON创建Item实例
factory Item.fromJson(Map<String, dynamic> json) {
  return Item(
    // 其他字段...
    enableReminder: (json['enableReminder'] as int? ?? 1) == 1,
    // 其他字段...
  );
}

💻 关键代码展示

1. 仓库层实现

class ItemRepository {
  final DatabaseHelper _databaseHelper = DatabaseHelper.instance;
  
  /// 添加物品
  Future<int> addItem(Item item) async {
    final map = item.toJson();
    return await _databaseHelper.insert(map);
  }
  
  /// 获取所有物品
  Future<List<Item>> getAllItems() async {
    final maps = await _databaseHelper.queryAllRows();
    return maps.map((map) => Item.fromJson(map)).toList();
  }
  
  /// 根据状态获取物品
  Future<List<Item>> getItemsByStatus(ItemStatus status) async {
    final maps = await _databaseHelper.queryRowsByStatus(status.index);
    return maps.map((map) => Item.fromJson(map)).toList();
  }
  
  /// 其他仓库方法...
}

2. 服务层实现

class ItemService {
  final ItemRepository _itemRepository = ItemRepository();
  
  /// 添加物品
  Future<int> addItem({
    required String name,
    required ItemType type,
    required DateTime purchaseDate,
    required DateTime expiryDate,
    String? description,
    int quantity = 1,
    bool enableReminder = true,
  }) {
    final now = DateTime.now();
    final item = Item(
      id: 'item_${DateTime.now().millisecondsSinceEpoch}',
      name: name,
      type: type,
      purchaseDate: purchaseDate,
      expiryDate: expiryDate,
      description: description,
      quantity: quantity,
      enableReminder: enableReminder,
      createdAt: now,
      updatedAt: now,
    );
    return _itemRepository.addItem(item);
  }
  
  /// 其他服务方法...
}

3. 状态筛选逻辑

/// 筛选物品
void _filterItems(ItemStatus? status) {
  setState(() {
    _filterStatus = status;
  });
}

/// 获取筛选后的物品
List<Item> get _filteredItems {
  if (_filterStatus == null) {
    return _items;
  }
  return _items.where((item) => item.status == _filterStatus).toList();
}

📊 项目流程图

1. 物品添加流程

验证失败

验证成功

用户点击添加按钮

打开添加物品页面

用户填写物品信息

表单验证

提示错误信息

调用添加物品服务

保存到数据库

返回主界面

刷新物品列表

2. 物品状态计算流程

获取当前日期

获取物品过期日期

计算剩余天数

剩余天数 < 0?

标记为已过期

剩余天数 <= 7?

标记为即将过期

标记为正常

3. 数据访问流程

UI层调用服务

服务层处理业务逻辑

调用仓库层方法

仓库层调用数据库助手

数据库助手执行SQL操作

返回结果给仓库层

仓库层转换数据格式

返回结果给服务层

服务层处理结果

返回结果给UI层

🎨 界面设计亮点

1. 视觉层次清晰

  • 使用卡片式布局区分不同功能区域
  • 采用不同颜色标识物品状态
  • 清晰的文字层级,重要信息突出显示

2. 交互友好

  • 流畅的动画效果
  • 直观的操作反馈
  • 便捷的添加和删除功能

3. 响应式设计

  • 适配不同屏幕尺寸
  • 合理的空间利用
  • 良好的触控体验

📱 鸿蒙平台适配

1. 开发环境配置

  • 安装华为DevEco Studio
  • 配置Flutter HarmonyOS插件
  • 创建HarmonyOS Flutter项目
  • 配置签名和权限

2. 权限管理

在鸿蒙平台上,需要申请必要的权限:

  • 文件存储权限:用于存储SQLite数据库
  • 网络权限(可选):用于未来扩展云同步功能
  • 通知权限(可选):用于过期提醒

3. 构建和发布

  • 使用DevEco Studio构建HarmonyOS应用包(HAP)
  • 配置应用信息和图标
  • 提交到华为应用市场

🔍 调试与测试

1. 代码质量检查

# 运行Flutter分析器
flutter analyze

# 运行测试
flutter test

# 检查依赖
flutter pub outdated

2. 鸿蒙设备调试

  • 使用华为模拟器或真机进行调试
  • 查看日志输出
  • 测试各种场景下的应用表现

📈 性能优化

  1. 数据库优化

    • 使用索引优化查询性能
    • 批量操作减少数据库访问次数
    • 定期清理过期数据
  2. UI优化

    • 使用ListView.builder实现懒加载
    • 合理使用缓存
    • 减少不必要的重建
  3. 内存管理

    • 及时释放资源
    • 避免内存泄漏
    • 使用弱引用处理长生命周期对象

🎯 项目总结

通过本项目,我们掌握了:

  • ✅ Flutter在鸿蒙平台上的开发流程
  • ✅ 分层架构设计和实现
  • ✅ SQLite数据库的使用和优化
  • ✅ 响应式UI设计原则
  • ✅ 状态管理和业务逻辑处理

🚀 结语

物品过期追踪器项目展示了鸿蒙+Flutter跨平台开发的强大能力。通过合理的架构设计、清晰的UI布局和完善的功能实现,我们成功打造了一款实用的物品管理工具。

在开发过程中,我们遇到了各种挑战,如数据库设计、状态管理、UI适配等,但通过团队协作和技术探索,我们都一一解决了这些问题。这个项目不仅提高了我们的技术水平,也让我们深刻理解了用户需求和产品设计的重要性。

📚 参考资料

  1. Flutter官方文档
  2. 鸿蒙开发者文档
  3. SQLite官方文档
  4. Flutter Architecture Blueprints
  5. Dart语言规范

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐