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

 

一、使用软件

DevEco Studio


鸿蒙官方集成开发环境,提供项目管理、代码编辑、模拟器调试、应用打包等全流程开发能力,是 Flutter-OH 应用开发的核心工具。

 

Flutter-OH SDK

面向 OpenHarmony 生态定制的 Flutter 跨平台开发工具包,支持 Dart 语言编译、鸿蒙平台适配、UI 组件渲染与应用构建


OpenHarmony 模拟器

DevEco Studio 内置的鸿蒙设备虚拟运行环境,无需物理真机即可完成 APP 界面预览、功能调试与兼容性验证。
 

 

二、核心内容

  1. 实现笔记收藏功能
  2. 收藏笔记自动置顶,优先展示重要笔记
  3. 收藏图标切换(空心星星 / 实心星星)
  4. 收藏状态永久保存,重启不重置
  5. 兼容前面:时间戳、搜索、增删改全部功能

 

三、操作步骤

步骤 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();
  1. _goEdit 保存后面加一行:
_sortNote();
  1. _goDelete 保存后面加一行:
_sortNote();

步骤 6:初始化加载完成自动排序

找到 _loadNotes 末尾添加:

_sortNote();

三、模拟器运行测试

  1. 收藏测试:点击星星图标,可切换收藏 / 取消收藏,星星颜色变化明显。

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

  1. 功能兼容:新增、编辑、删除、搜索全部不受影响。
  2. 持久化测试:重启模拟器,收藏状态保留,排序位置不变。
  3. 界面测试:图标美观,点击流畅,无闪退报错。

四、总代码

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:笔记标星收藏与置顶排序功能实现

        为优化笔记管理效率,方便用户快速定位重要资料,本篇在结构化笔记模型基础上,开发标星收藏与置顶排序功能。普通记事本缺乏重要笔记标记能力,随着笔记数量增多,关键内容容易被淹没,因此收藏置顶是轻量化笔记软件不可或缺的高级功能。本次开发依托前期已完成的数据模型、时间戳记录、本地持久化等功能,新增收藏标记逻辑,完善笔记分级管理体系,进一步贴合鸿蒙应用软件简洁高效的使用需求。

        本次开发在原有笔记实体类中,利用预留的布尔收藏字段进行状态判定,无需重构数据结构,降低代码改动成本。在列表右侧增设星星图标作为收藏交互入口,黄色实心星星代表已收藏,灰色空心星星代表普通笔记,视觉区分直观易懂。点击星星即可切换收藏状态,逻辑简单、交互符合移动端通用操作习惯。

        为优化展示逻辑,编写自定义排序方法,程序自动将收藏笔记筛选置顶,普通笔记后置排列,实现重要内容优先展示。每次进行新增、编辑、删除、收藏操作后,系统自动重排列表顺序,保证置顶逻辑实时生效。所有收藏状态同步写入本地持久化文件,应用重启后不会丢失标记,长期使用无需重复收藏。

        开发过程中保留全部历史功能,时间戳记录、文本预览、关键词检索、增删修改均正常兼容。同时优化图标点击区域,防止误触,适配鸿蒙触控交互标准。针对边界场景进行调试,多条收藏笔记自动有序排列,取消收藏后自动下沉至普通列表,排序逻辑严谨不乱。

        经过模拟器多项测试,收藏切换响应迅速、排序规则清晰、数据存储稳定,界面无卡顿、无错乱。本篇完成收藏置顶功能,完善了笔记分级管理体系,提升信息查找效率,为后续笔记分类、卡片美化等进阶功能奠定扎实基础。

 

Logo

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

更多推荐