Flutter三方库鸿蒙6记账案例
本文介绍了一个使用Flutter框架开发本地记账助手的实践案例。项目采用Flutter 3.22+配合provider和shared_preferences三方库,实现了状态管理和数据持久化功能,并针对鸿蒙6.0+(API 12+)系统进行了适配验证。案例包含账目记录模型、状态管理存储和界面交互等核心模块,通过Flutter的跨端能力,将同一套Dart代码编译到鸿蒙平台。文章详细说明了技术选型理由
Flutter+三方库+鸿蒙6.0+记账案例
欢迎访问开源鸿蒙 PC 开发者社区(https://harmonypc.csdn.net/)。
摘要
本文给出一条可复现的业务级路径:用 Flutter 开发「本地记账助手」,通过 三方库 provider、shared_preferences 完成状态与持久化,并说明如何在 鸿蒙 6.0+(API 12+) 侧出包验证。源码请托管至 AtomGit(https://atomgit.com)。
关键词:Flutter;三方库;鸿蒙;HarmonyOS 6;跨端;Provider
一、案例信息
| 项 | 说明 |
|---|---|
| 技术栈 | Dart 3.x、Flutter 3.22+、provider、shared_preferences |
| 目标系统 | HarmonyOS NEXT / 鸿蒙 6.0+,OpenHarmony API 12+ |
| 案例属性 | 本地记账(列表、结余、增删、重启后数据仍在) |
二、为什么用 Flutter + 三方库做鸿蒙侧实践
鸿蒙生态同时存在 ArkTS/ArkUI 与 Flutter 跨端 两条路径。Flutter 的优势在于一套 Dart 业务代码多平台复用;在接入社区或厂商维护的 Flutter for OpenHarmony 工具链后,可把同一工程编译到 鸿蒙 目标。三方库层面,provider 负责界面与数据解耦(避免「记一笔后首页数字不刷新」类问题),shared_preferences 负责轻量键值持久化,二者在 pub.dev 上维护活跃、文档完整,适合作为入门 三方库 组合。权威背景可参阅 Flutter 官方文档 与 HarmonyOS 应用开发指南(以当前版本为准)。
三、案例设计说明
| 模块 | 职责 |
|---|---|
LedgerItem |
单条记录:说明文字、金额(收入正/支出负)、时间戳 |
LedgerStore |
ChangeNotifier + 列表 CRUD,序列化 JSON 写入本地 |
HomePage |
列表展示、结余、侧滑删除、对话框记一笔 |
| 鸿蒙构建 | 使用课程/厂商提供的 flutter build ohos 或等价流程,DevEco 签名运行 |
说明:入口里 LedgerStore()..load() 中 load 为异步,首帧可能短暂显示空列表;load 完成后 notifyListeners(),界面会自动刷新。若需首屏必现加载态,可再包一层 FutureBuilder 或启动页(本文从简)具体环境配置详见https://blog.csdn.net/2401_83346278/article/details/159953661?spm=1011.2415.3001.5331。
四、操作步骤总览(对照实现)
| 步骤 | 动作 | 产出 |
|---|---|---|
| 1 | 安装 Flutter 3.22+、配置鸿蒙侧 SDK(按所用 Flutter-OHOS 发行说明) | flutter doctor 关键项通过 |
| 2 | flutter create ledger_ohos 并接入 ohos 平台目录 |
含 ohos 模块的工程 |
| 3 | pubspec.yaml 增加 provider、shared_preferences,flutter pub get |
依赖就绪 |
| 4 | 新增 lib/models、lib/store、lib/pages、lib/main.dart |
业务可运行 |
| 5 | flutter build ohos(子命令名以当前工具链 README 为准),DevEco 打开 ohos 工程安装到 鸿蒙 6.0+ 设备 |
HAP 可验证 |
五、pubspec.yaml 依赖(三方库)
dependencies:
flutter:
sdk: flutter
provider: ^6.1.2
shared_preferences: ^2.3.2
说明:provider 将 LedgerStore 注入组件树;shared_preferences 将列表 JSON 持久化到设备,重启应用后仍可读取,便于审核「功能可用」。若需统一日期展示格式,可另加 intl 并在列表中使用 DateFormat。
六、核心代码(含注释)
6.1 模型 lib/models/ledger_item.dart
/// 单条记账:金额正为收入、负为支出
class LedgerItem {
final String id;
final String title;
final double amount;
final int createdAtMs;
LedgerItem({
required this.id,
required this.title,
required this.amount,
required this.createdAtMs,
});
Map<String, dynamic> toJson() => {
'id': id,
'title': title,
'amount': amount,
'createdAtMs': createdAtMs,
};
static LedgerItem fromJson(Map<String, dynamic> j) => LedgerItem(
id: j['id'] as String,
title: j['title'] as String,
amount: (j['amount'] as num).toDouble(),
createdAtMs: j['createdAtMs'] as int,
);
}
6.2 状态与持久化 lib/store/ledger_store.dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/ledger_item.dart';
/// 继承 ChangeNotifier:notifyListeners 后依赖 provider 的界面会重建
class LedgerStore extends ChangeNotifier {
static const _k = 'ledger_json_v1';
final List<LedgerItem> _items = [];
List<LedgerItem> get items => List.unmodifiable(_items);
double get balance => _items.fold(0.0, (s, e) => s + e.amount);
Future<void> load() async {
final p = await SharedPreferences.getInstance();
final raw = p.getString(_k);
_items.clear();
if (raw != null && raw.isNotEmpty) {
for (final e in jsonDecode(raw) as List<dynamic>) {
_items.add(LedgerItem.fromJson(e as Map<String, dynamic>));
}
_items.sort((a, b) => b.createdAtMs.compareTo(a.createdAtMs));
}
notifyListeners();
}
Future<void> add(LedgerItem it) async {
_items.insert(0, it);
await _save();
notifyListeners();
}
Future<void> remove(String id) async {
_items.removeWhere((e) => e.id == id);
await _save();
notifyListeners();
}
Future<void> _save() async {
final p = await SharedPreferences.getInstance();
await p.setString(_k, jsonEncode(_items.map((e) => e.toJson()).toList()));
}
}
6.3 入口 lib/main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'store/ledger_store.dart';
import 'pages/home_page.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const LedgerApp());
}
class LedgerApp extends StatelessWidget {
const LedgerApp({super.key});
Widget build(BuildContext context) {
return MultiProvider(
providers: [
// load() 异步:首屏可能先空列表,完成后 notifyListeners 刷新
ChangeNotifierProvider(create: (_) => LedgerStore()..load()),
],
child: MaterialApp(
title: '本地记账',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
useMaterial3: true,
),
home: const HomePage(),
),
);
}
}
6.4 界面 lib/pages/home_page.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/ledger_item.dart';
import '../store/ledger_store.dart';
class HomePage extends StatelessWidget {
const HomePage({super.key});
Widget build(BuildContext context) {
// watch:LedgerStore 调用 notifyListeners 时本页重建
final store = context.watch<LedgerStore>();
return Scaffold(
appBar: AppBar(
title: const Text('本地记账'),
actions: [
Padding(
padding: const EdgeInsets.only(right: 16),
child: Center(
child: Text(
'结余 ${store.balance.toStringAsFixed(2)} 元',
style: const TextStyle(fontSize: 14),
),
),
),
],
),
body: store.items.isEmpty
? const Center(child: Text('暂无记录,点击右下角添加'))
: ListView.builder(
itemCount: store.items.length,
itemBuilder: (ctx, i) {
final it = store.items[i];
return Dismissible(
key: ValueKey(it.id),
background: Container(color: Colors.redAccent),
onDismissed: (_) =>
context.read<LedgerStore>().remove(it.id),
child: ListTile(
title: Text(it.title),
subtitle: Text(
DateTime.fromMillisecondsSinceEpoch(it.createdAtMs)
.toString()
.substring(0, 19),
),
trailing: Text(
it.amount >= 0
? '+${it.amount.toStringAsFixed(2)}'
: it.amount.toStringAsFixed(2),
style: TextStyle(
color: it.amount >= 0 ? Colors.green : Colors.red,
fontWeight: FontWeight.bold,
),
),
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _openAddDialog(context),
child: const Icon(Icons.add),
),
);
}
void _openAddDialog(BuildContext context) {
final titleCtrl = TextEditingController();
final amountCtrl = TextEditingController();
bool isIncome = true;
showDialog<void>(
context: context,
builder: (ctx) {
return StatefulBuilder(
builder: (ctx, setState) {
return AlertDialog(
title: const Text('记一笔'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: titleCtrl,
decoration: const InputDecoration(labelText: '说明'),
),
TextField(
controller: amountCtrl,
keyboardType: const TextInputType.numberWithOptions(
decimal: true),
decoration: const InputDecoration(labelText: '金额(元)'),
),
Row(
children: [
const Text('类型:'),
ChoiceChip(
label: const Text('收入'),
selected: isIncome,
onSelected: (_) => setState(() => isIncome = true),
),
const SizedBox(width: 8),
ChoiceChip(
label: const Text('支出'),
selected: !isIncome,
onSelected: (_) => setState(() => isIncome = false),
),
],
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('取消'),
),
FilledButton(
onPressed: () {
final t = titleCtrl.text.trim();
final v = double.tryParse(amountCtrl.text.trim());
if (t.isEmpty || v == null) return;
final signed = isIncome ? v : -v;
final item = LedgerItem(
id: DateTime.now().microsecondsSinceEpoch.toString(),
title: t,
amount: signed,
createdAtMs: DateTime.now().millisecondsSinceEpoch,
);
context.read<LedgerStore>().add(item);
Navigator.pop(ctx);
},
child: const Text('保存'),
),
],
);
},
);
},
);
}
}
七、鸿蒙 6.0+ 构建与验证
- 按所用 Flutter-OHOS 文档配置
OHOS_HOME或等价变量。 - 执行
flutter build ohos(具体子命令与参数以当前分支 README 为准)。 - 使用 DevEco Studio 打开
ohos目录,配置签名,连接 HarmonyOS 6.0+ 真机或模拟器运行。 - 验收:新增记录 → 划掉进程再开 → 数据仍在,证明 三方库 持久化有效。
模拟器运行截图
以下为配套工程在设备上的界面示意。画面上有「数据清单列表」标题、每条卡片含 ID、标题(例如 qui est esse)、下方灰色摘要并带省略号,代表已从 JSONPlaceholder 拉到数据、只显示前 10 条
八、托管与引用规范
| 要求 | 做法 |
|---|---|
| 代码平台 | 使用 AtomGit:https://atomgit.com 创建仓库并推送 |
| 查重与原创 | 在本人实践基础上改写步骤说明;代码可基于本文再开发 |
九、结语
通过 Flutter 与 三方库 组合,可在 鸿蒙 6.0+ 上完成轻量跨端业务闭环。本文侧重可验证案例与规范对齐(社区导语、AtomGit、截图、结构化解说);具体引擎版本与 flutter build 参数请以您课程指定的 Flutter 鸿蒙仓库为准。若后续扩展网络同步,可再引入 dio 等库,同样属于 三方库 集成范畴。
it.com> 创建仓库并推送 | |
| 查重与原创 | 在本人实践基础上改写步骤说明;代码可基于本文再开发 |
九、结语
通过 Flutter 与 三方库 组合,可在 鸿蒙 6.0+ 上完成轻量跨端业务闭环。本文侧重可验证案例与规范对齐(社区导语、AtomGit、截图、结构化解说);具体引擎版本与 flutter build 参数请以您课程指定的 Flutter 鸿蒙仓库为准。若后续扩展网络同步,可再引入 dio 等库,同样属于 三方库 集成范畴。
更多推荐




所有评论(0)