Flutter-OH 鸿蒙工具类应用实战 Day6:笔记时间戳生成与列表预览优化
前五篇完成了笔记新增、编辑、删除、搜索与本地存储基础功能,但数据仅以简单字符串格式保存,无法记录笔记生成时间与修改轨迹,不符合正规工具类应用开发规范。本篇对原有数据架构进行重构优化,自定义笔记实体模型,实现自动生成创建时间、实时更新修改时间,同时优化列表预览效果,提升应用专业性与数据完整性。本次升级完全兼容历史功能,搜索、新增、编辑、删除逻辑不受改动影响,数据无缝迁移。
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
一、使用软件
DevEco Studio
鸿蒙官方集成开发环境,提供项目管理、代码编辑、模拟器调试、应用打包等全流程开发能力,是 Flutter-OH 应用开发的核心工具。

Flutter-OH SDK
面向 OpenHarmony 生态定制的 Flutter 跨平台开发工具包,支持 Dart 语言编译、鸿蒙平台适配、UI 组件渲染与应用构建
OpenHarmony 模拟器
DevEco Studio 内置的鸿蒙设备虚拟运行环境,无需物理真机即可完成 APP 界面预览、功能调试与兼容性验证。
二、核心内容
- 重构数据结构,不再单纯保存字符串,升级为笔记对象
- 自动生成创建时间、修改时间
- 列表只显示简短预览,不全铺长文本
- 编辑笔记自动更新修改时间
- 完全兼容之前:新增、删除、搜索、本地存储
- 适配鸿蒙时间格式,排版更专业
三、操作步骤
步骤 1:升级数据模型(新增笔记实体类)
原本你只能存纯文本,现在要存文本 + 创建时间 + 修改时间 + 收藏状态。在 lib 里面新建文件夹 models,新建文件 note_model.dart写入模型代码(专门存放笔记结构)。


class NoteModel {
String content; // 笔记内容
String createTime; // 创建时间
String updateTime; // 修改时间
bool isStar; // 收藏状态
NoteModel({
required this.content,
required this.createTime,
required this.updateTime,
this.isStar = false,
});
// 转为json(保存本地)
Map<String,dynamic> toJson(){
return {
"content":content,
"createTime":createTime,
"updateTime":updateTime,
"isStar":isStar,
};
}
// 从json读取
static NoteModel fromJson(Map<String,dynamic> map){
return NoteModel(
content: map["content"],
createTime: map["createTime"],
updateTime: map["updateTime"],
isStar: map["isStar"],
);
}
}
步骤 2:修改存储工具类 note_storage.dart
之前只能存字符串,现在改成存储笔记对象数组,适配时间保存。全部替换:
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/note_model.dart';
class NoteStorage {
static const String _key = 'note_list';
// 保存笔记列表
static Future<void> saveNotes(List<NoteModel> notes) async {
final prefs = await SharedPreferences.getInstance();
List<String> jsonList = notes.map((e)=>jsonEncode(e.toJson())).toList();
await prefs.setStringList(_key, jsonList);
}
// 读取笔记列表
static Future<List<NoteModel>> loadNotes() async {
final prefs = await SharedPreferences.getInstance();
List<String>? strList = prefs.getStringList(_key);
if(strList==null) return [];
return strList.map((e)=>NoteModel.fromJson(jsonDecode(e))).toList();
}
}
步骤 3:编写时间格式化工具(生成当前时间)
打开 utils 新建 time_util.dart

import 'dart:ui';
class TimeUtil{
// 获取当前时间 年-月-日 时:分
static String getNowTime(){
DateTime now = DateTime.now();
return "${now.year}-${now.month}-${now.day} ${now.hour}:${now.minute}";
}
}
步骤 4:修改 main.dart 变量
删除旧的 String 列表,替换:
List<NoteModel> _allNotes = [];
List<NoteModel> _showNotes = [];
步骤 5:修改加载方法(读取带时间的笔记)
Future<void> _loadNotes() async {
final list = await NoteStorage.loadNotes();
setState(() {
_allNotes = list;
_showNotes = List.from(_allNotes);
});
}
步骤 6:新增笔记时自动生成时间
Future<void> _addNote() async {
final newText = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const MarkdownEditPage()),
);
if (newText != null && newText.trim().isNotEmpty) {
String time = TimeUtil.getNowTime();
setState(() {
_allNotes.add(
NoteModel(
content: newText,
createTime: time,
updateTime: time,
),
);
_searchNotes();
});
await _saveNotes();
}
}
步骤 7:编辑笔记自动更新修改时间
Future<void> _goEdit(int index) async {
final realIndex = _allNotes.indexOf(_showNotes[index]);
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MarkdownEditPage(
initialContent: _allNotes[realIndex].content,
),
),
);
if (result != null) {
String newTime = TimeUtil.getNowTime();
setState(() {
_allNotes[realIndex].content = result;
_allNotes[realIndex].updateTime = newTime;
_searchNotes();
});
await _saveNotes();
}
}
步骤 8:搜索方法改成匹配笔记内容
void _searchNotes() {
String key = _searchController.text.trim();
setState(() {
if (key.isEmpty) {
_showNotes = List.from(_allNotes);
} else {
_showNotes = _allNotes
.where((note) => note.content.contains(key))
.toList();
}
});
}
步骤 9:列表 UI 升级(显示简短预览 + 时间)
把 ListTile 改成:
ListTile(
title: Text(
// 最多显示20个字预览
_showNotes[index].content.length>20
? "${_showNotes[index].content.substring(0,20)}..."
: _showNotes[index].content,
),
subtitle: Text(
"创建:${_showNotes[index].createTime}\n修改:${_showNotes[index].updateTime}",
style: TextStyle(fontSize: 11,color: Colors.grey),
),
onTap: () => _goEdit(index),
onLongPress: () => _goDelete(index),
),
步骤 10:模拟器运行测试
- 时间测试:新增笔记自动生成时间,编辑笔记修改时间同步刷新。

- 预览测试:长文本自动截断加省略号,短文本完整展示。

- 功能测试:新增、编辑、删除、搜索功能运行正常,无卡顿闪退。
- 数据测试:重启应用后笔记与时间信息保留,持久化生效。
- 兼容测试:界面布局适配鸿蒙模拟器,交互流畅无误。
四、总代码
import 'package:flutter/material.dart';
import 'utils/note_storage.dart';
import 'utils/time_util.dart';
import 'pages/markdown_edit_page.dart';
import 'models/note_model.dart';
void main() {
runApp(const NoteApp());
}
class NoteApp extends StatelessWidget {
const NoteApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Note App',
debugShowCheckedModeBanner: false,
theme: ThemeData(primarySwatch: Colors.blue),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<NoteModel> _allNotes = [];
List<NoteModel> _showNotes = [];
final TextEditingController _searchController = TextEditingController();
@override
void initState() {
super.initState();
_loadNotes();
_searchController.addListener(_searchNotes);
}
Future<void> _loadNotes() async {
final list = await NoteStorage.loadNotes();
setState(() {
_allNotes = list;
_showNotes = List.from(_allNotes);
});
}
Future<void> _saveNotes() async {
await NoteStorage.saveNotes(_allNotes);
}
void _searchNotes() {
String key = _searchController.text.trim();
setState(() {
if (key.isEmpty) {
_showNotes = List.from(_allNotes);
} else {
_showNotes = _allNotes
.where((note) => note.content.contains(key))
.toList();
}
});
}
Future<void> _goEdit(int index) async {
final realIndex = _allNotes.indexOf(_showNotes[index]);
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MarkdownEditPage(
initialContent: _allNotes[realIndex].content,
),
),
);
if (result != null) {
String newTime = TimeUtil.getNowTime();
setState(() {
_allNotes[realIndex].content = result;
_allNotes[realIndex].updateTime = newTime;
_searchNotes();
});
await _saveNotes();
}
}
Future<void> _goDelete(int index) async {
final realIndex = _allNotes.indexOf(_showNotes[index]);
bool? confirm = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text("确认删除"),
content: const Text("确定要删除这条笔记吗?"),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text("取消"),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text("删除", style: TextStyle(color: Colors.red)),
),
],
),
);
if (confirm == true) {
setState(() {
_allNotes.removeAt(realIndex);
_searchNotes();
});
await _saveNotes();
}
}
Future<void> _addNote() async {
final newText = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const MarkdownEditPage()),
);
if (newText != null && newText.trim().isNotEmpty) {
String time = TimeUtil.getNowTime();
setState(() {
_allNotes.add(
NoteModel(
content: newText,
createTime: time,
updateTime: time,
),
);
_searchNotes();
});
await _saveNotes();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("鸿蒙 Note 记事本"),
bottom: PreferredSize(
preferredSize: const Size.fromHeight(50),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
child: TextField(
controller: _searchController,
decoration: const InputDecoration(
hintText: "搜索笔记内容",
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.search),
),
),
),
),
),
body: _showNotes.isEmpty
? const Center(
child: Text(
"暂无笔记或无搜索结果",
style: TextStyle(fontSize: 16, color: Colors.grey),
),
)
: ListView.builder(
itemCount: _showNotes.length,
itemBuilder: (context, index) => ListTile(
title: Text(
_showNotes[index].content.length > 20
? "${_showNotes[index].content.substring(0, 20)}..."
: _showNotes[index].content,
),
subtitle: Text(
"创建:${_showNotes[index].createTime}\n修改:${_showNotes[index].updateTime}",
style: TextStyle(fontSize: 11, color: Colors.grey),
),
onTap: () => _goEdit(index),
onLongPress: () => _goDelete(index),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _addNote,
child: const Icon(Icons.add),
),
);
}
}
五、小结---Flutter-OH 鸿蒙工具类应用实战 Day6:笔记时间戳生成与列表预览优化
在标准记事本软件开发流程中,数据结构化优化是项目进阶开发的关键环节。前五篇完成了笔记新增、编辑、删除、搜索与本地存储基础功能,但数据仅以简单字符串格式保存,无法记录笔记生成时间与修改轨迹,不符合正规工具类应用开发规范。本篇对原有数据架构进行重构优化,自定义笔记实体模型,实现自动生成创建时间、实时更新修改时间,同时优化列表预览效果,提升应用专业性与数据完整性。
本次开发首先新建笔记实体模型类,将原本单一文本字段扩充为内容、创建时间、修改时间、收藏状态四大属性,实现笔记数据结构化管理。其次重构本地存储工具,将原本存储字符串列表的逻辑升级为 JSON 对象序列化存储,保证时间信息、编辑记录永久保存,适配持久化需求。同时编写时间工具类,统一格式化输出年月日时分标准时间,贴合鸿蒙系统时间显示规范。
功能逻辑优化方面,新增笔记时系统自动获取当前时间作为创建时间;用户编辑笔记后同步刷新修改时间,精准记录每一次改动轨迹。列表展示层面增加文本截取逻辑,长笔记自动截断并添加省略号,避免页面文字堆砌;同时在笔记下方展示两行时间信息,清晰区分创建与修改记录,布局层次分明、简洁直观。
本次升级完全兼容历史功能,搜索、新增、编辑、删除逻辑不受改动影响,数据无缝迁移。针对边界场景进行调试适配,包括空白笔记过滤、超长文本截取、时间格式错乱防护等优化,保证模拟器运行稳定无报错。
通过本次结构化重构,项目摆脱了简单文本存储模式,具备了正规应用软件的数据模型架构,为后续收藏、分类、标签筛选等高级功能打下坚实基础。本篇优化进一步加深了开发者对 Dart 实体类、JSON 序列化、工具类封装的理解,完成了记事本从简易 demo 向规范化工程项目的进阶升级。
更多推荐



所有评论(0)