Flutter-OH 鸿蒙工具类应用实战 Day7:笔记标星收藏与置顶排序功能实现
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net。
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
一、使用软件
DevEco Studio
鸿蒙官方集成开发环境,提供项目管理、代码编辑、模拟器调试、应用打包等全流程开发能力,是 Flutter-OH 应用开发的核心工具。

Flutter-OH SDK
面向 OpenHarmony 生态定制的 Flutter 跨平台开发工具包,支持 Dart 语言编译、鸿蒙平台适配、UI 组件渲染与应用构建
OpenHarmony 模拟器
DevEco Studio 内置的鸿蒙设备虚拟运行环境,无需物理真机即可完成 APP 界面预览、功能调试与兼容性验证。
二、核心内容
- 实现笔记收藏功能
- 收藏笔记自动置顶,优先展示重要笔记
- 收藏图标切换(空心星星 / 实心星星)
- 收藏状态永久保存,重启不重置
- 兼容前面:时间戳、搜索、增删改全部功能
三、操作步骤
步骤 1:修改笔记模型(无需新建文件)
打开 models/note_model.dart里面本来就有 isStar,不用改代码,已经预留好了。
步骤 2:首页列表右侧添加收藏按钮
打开 main.dart,找到列表 ListTile,新增尾部星星图标:
trailing: IconButton(
icon: Icon(
_showNotes[index].isStar ? Icons.star : Icons.star_border,
color: _showNotes[index].isStar ? Colors.amber : Colors.grey,
),
onPressed: (){
_starNote(index);
},
),
步骤 3:新增收藏切换方法
粘贴这个方法:
// 收藏切换
void _starNote(int index){
int realIndex = _allNotes.indexOf(_showNotes[index]);
setState(() {
// 取反:收藏变未收藏,未收藏变收藏
_allNotes[realIndex].isStar = !_allNotes[realIndex].isStar;
_sortNote();
});
_saveNotes();
}
步骤 4:新增排序方法(收藏置顶)
// 收藏置顶排序
void _sortNote(){
// 收藏放前面,普通放后面
List<NoteModel> starList = _allNotes.where((e)=>e.isStar).toList();
List<NoteModel> normalList = _allNotes.where((e)=>!e.isStar).toList();
setState(() {
_allNotes = [...starList,...normalList];
_searchNotes();
});
}
步骤 5:新增、编辑、删除后自动排序
在 _addNote 保存后面加一行:
_sortNote();
- 在
_goEdit保存后面加一行:
_sortNote();
- 在
_goDelete保存后面加一行:
_sortNote();
步骤 6:初始化加载完成自动排序
找到 _loadNotes 末尾添加:
_sortNote();
三、模拟器运行测试
- 收藏测试:点击星星图标,可切换收藏 / 取消收藏,星星颜色变化明显。

- 排序测试:收藏笔记自动置顶,优先展示。

- 功能兼容:新增、编辑、删除、搜索全部不受影响。
- 持久化测试:重启模拟器,收藏状态保留,排序位置不变。
- 界面测试:图标美观,点击流畅,无闪退报错。
四、总代码
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);
});
_sortNote();
}
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();
}
});
}
// 收藏置顶排序
void _sortNote(){
List<NoteModel> starList = _allNotes.where((e)=>e.isStar).toList();
List<NoteModel> normalList = _allNotes.where((e)=>!e.isStar).toList();
setState(() {
_allNotes = [...starList,...normalList];
_searchNotes();
});
}
// 收藏切换
void _starNote(int index){
int realIndex = _allNotes.indexOf(_showNotes[index]);
setState(() {
_allNotes[realIndex].isStar = !_allNotes[realIndex].isStar;
_sortNote();
});
_saveNotes();
}
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();
});
_sortNote();
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();
});
_sortNote();
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();
});
_sortNote();
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),
),
trailing: IconButton(
icon: Icon(
_showNotes[index].isStar ? Icons.star : Icons.star_border,
color: _showNotes[index].isStar ? Colors.amber : Colors.grey,
),
onPressed: (){
_starNote(index);
},
),
onTap: () => _goEdit(index),
onLongPress: () => _goDelete(index),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _addNote,
child: const Icon(Icons.add),
),
);
}
}
五、小结---Flutter-OH 鸿蒙工具类应用实战 Day7:笔记标星收藏与置顶排序功能实现
为优化笔记管理效率,方便用户快速定位重要资料,本篇在结构化笔记模型基础上,开发标星收藏与置顶排序功能。普通记事本缺乏重要笔记标记能力,随着笔记数量增多,关键内容容易被淹没,因此收藏置顶是轻量化笔记软件不可或缺的高级功能。本次开发依托前期已完成的数据模型、时间戳记录、本地持久化等功能,新增收藏标记逻辑,完善笔记分级管理体系,进一步贴合鸿蒙应用软件简洁高效的使用需求。
本次开发在原有笔记实体类中,利用预留的布尔收藏字段进行状态判定,无需重构数据结构,降低代码改动成本。在列表右侧增设星星图标作为收藏交互入口,黄色实心星星代表已收藏,灰色空心星星代表普通笔记,视觉区分直观易懂。点击星星即可切换收藏状态,逻辑简单、交互符合移动端通用操作习惯。
为优化展示逻辑,编写自定义排序方法,程序自动将收藏笔记筛选置顶,普通笔记后置排列,实现重要内容优先展示。每次进行新增、编辑、删除、收藏操作后,系统自动重排列表顺序,保证置顶逻辑实时生效。所有收藏状态同步写入本地持久化文件,应用重启后不会丢失标记,长期使用无需重复收藏。
开发过程中保留全部历史功能,时间戳记录、文本预览、关键词检索、增删修改均正常兼容。同时优化图标点击区域,防止误触,适配鸿蒙触控交互标准。针对边界场景进行调试,多条收藏笔记自动有序排列,取消收藏后自动下沉至普通列表,排序逻辑严谨不乱。
经过模拟器多项测试,收藏切换响应迅速、排序规则清晰、数据存储稳定,界面无卡顿、无错乱。本篇完成收藏置顶功能,完善了笔记分级管理体系,提升信息查找效率,为后续笔记分类、卡片美化等进阶功能奠定扎实基础。
更多推荐



所有评论(0)