文本去重工具技术解析文档

一、项目背景概述

本项目是一个基于 Flutter 框架开发的文本去重工具应用,专为 OpenHarmony 平台设计。应用的核心功能是对用户输入的多行文本进行去重处理,去除重复的行,保留唯一的行,帮助用户快速清理重复数据。

从产品定位来看,这是一个实用型文本处理工具,面向需要处理大量文本数据的用户群体,如数据处理人员、内容编辑、开发者等。在日常工作中,经常会遇到需要去除重复行的场景,如整理邮件列表、清理数据导出结果、合并多个文档等,本应用提供了一个简单快捷的解决方案。

技术层面,应用采用 Flutter 的 Material Design 3 设计规范,使用深紫色作为主题色。应用界面分为输入区、操作区和输出区三大部分,结构清晰,操作直观。用户只需将文本粘贴到输入框,点击去重按钮即可得到结果。

应用的核心算法利用了 Dart 语言中 Set 数据结构的去重特性,将文本按行分割后转换为 Set 自动去重,再重新组合为文本。这种实现方式简洁高效,充分利用了语言内置的数据结构能力。

二、架构分析

2.1 整体架构图

应用入口 main

根组件 MaterialApp

首页组件 Scaffold

文本去重核心组件

输入区域

操作按钮区域

输出区域

说明区域

输入文本框

行数统计

清空按钮

输出文本框

行数统计

复制按钮

2.2 去重处理流程图

用户输入文本

点击去重按钮

输入文本是否为空?

显示提示: 请输入要去重的文本

按换行符分割为行列表

记录原始行数

转换为 Set 自动去重

记录去重后行数

重新用换行符连接为文本

设置输出文本框内容

显示提示: 去重完成

2.3 架构层次说明

应用采用简洁的两层组件架构:

第一层:应用根层级
负责应用的全局配置,包括主题、标题等。使用 MaterialApp 作为根组件,提供 Material Design 风格的视觉规范。首页使用 Scaffold 提供基础的页面结构,包括应用栏和可滚动的主体内容。

第二层:功能核心层
文本去重核心组件封装了全部的去重功能,包括输入、处理和输出。这是一个自包含的状态型组件,内部管理输入输出的文本控制器和统计数据。组件内部按照功能划分为四个区域:输入区域、操作区域、输出区域和说明区域。

这种集中式的设计适合功能相对单一的工具类应用,所有相关逻辑都在一个组件内,便于理解和维护。

三、入口组件流程

3.1 应用启动流程

应用的入口函数 main 调用 runApp 方法启动应用。根组件是一个无状态组件,返回 MaterialApp 实例,配置了应用标题、深紫色主题和 Material 3 支持。

首页组件是一个状态型组件,但其状态类非常简洁,构建方法只返回一个包含文本去重组件的 Scaffold。应用栏标题为"文本去重工具",采用深紫色背景和白色前景色。

主体内容使用 SingleChildScrollView 包裹,确保在小屏幕设备上内容可以滚动查看,避免溢出问题。内部是一个垂直列布局,只包含一个文本去重核心组件。

3.2 组件职责划分

首页组件:负责页面框架的搭建,提供应用栏和基础布局结构。本身不持有业务状态,只作为容器存在。

文本去重核心组件:负责全部的去重业务逻辑,包括输入管理、去重计算、结果展示等。是一个自包含的功能模块。

这种职责划分使得首页组件非常轻量,核心功能集中在一个组件中,对于简单的工具应用来说是合理的设计选择。

四、核心组件逐段解析

4.1 文本去重核心组件

文本去重核心组件是整个应用的主体,是一个状态型组件,封装了所有去重相关的功能。

状态变量:

  • 输入文本控制器:管理输入文本框的内容
  • 输出文本控制器:管理输出文本框的内容
  • 原始行数统计:记录去重前的行数
  • 去重后行数统计:记录去重后的行数

两个文本控制器分别管理输入和输出,使得输入和输出的状态独立可控。输出文本框设置为只读,用户不能直接修改去重结果。

核心方法:

去重方法是组件的核心功能方法,执行完整的去重流程:

  1. 获取输入文本
  2. 非空验证,为空则显示提示并返回
  3. 按换行符分割为行列表
  4. 记录原始行数
  5. 转换为 Set 实现去重
  6. 记录去重后的行数
  7. 重新连接为文本字符串
  8. 设置输出文本框内容
  9. 显示去重结果提示

清空方法用于清空所有输入输出和统计数据,重置到初始状态。

复制方法用于将去重结果复制到剪贴板。

生命周期管理:
组件在 dispose 方法中释放两个文本控制器的资源,确保内存安全。这是 Flutter 中使用控制器的标准最佳实践。

4.2 输入区域

输入区域包含输入文本框、行数统计和清空按钮三个部分。

输入文本框:
使用 TextField 组件,最多显示6行,内容超出时可滚动。没有边框,通过外部容器的边框来实现视觉边界。设置了占位提示文字,引导用户正确输入。

行数统计:
显示在输入区域左下角,展示当前输入的行数。文字颜色为灰色,字号较小,作为辅助信息存在。

清空按钮:
使用 ElevatedButton.icon 图标按钮,浅灰色背景,深紫色文字。点击后清空输入和输出的所有内容,重置统计数据。

4.3 操作按钮区域

操作区域居中显示一个大的去重按钮,使用 ElevatedButton.icon,带有过滤列表图标和"去除重复行"文字。深紫色背景,白色文字,圆角矩形,较大的内边距,突出主要操作。

这个按钮是应用的核心操作按钮,视觉上突出醒目,引导用户点击。

4.4 输出区域

输出区域的结构与输入区域对称,包含输出文本框、行数统计和复制按钮。

输出文本框:
与输入框样式相同,但设置为只读模式,用户不能编辑去重结果,只能查看和复制。

行数统计:
显示在输出区域左下角,展示去重后的行数。文字颜色为绿色,与输入区域的灰色形成对比,直观地表示这是处理后的结果。

复制按钮:
使用图标按钮,带有复制图标和"复制"文字。点击后将结果复制到剪贴板。

4.5 说明区域

说明区域位于组件底部,使用浅紫色背景的容器包裹,包含使用说明文字。说明以列表形式列出了4条使用步骤,帮助用户快速了解如何使用这个工具。

五、状态管理

5.1 状态架构

本应用采用组件内状态管理方案,所有状态都集中在文本去重核心组件内部管理。这种方案对于功能单一的工具类应用来说简单直接,不需要引入额外的状态管理库。

状态分类:

输入相关状态:

  • 输入文本控制器:管理输入文本内容
  • 原始行数统计:记录输入的行数

输出相关状态:

  • 输出文本控制器:管理输出文本内容
  • 去重后行数统计:记录输出的行数

5.2 状态更新流程

状态更新主要发生在以下几个时机:

用户输入时:输入文本控制器自动管理输入内容的变化,但行数统计不会实时更新,只有在执行去重操作时才会更新行数。

点击去重时:执行完整的去重计算,更新输出文本和两个行数统计。这是最主要的状态更新时机。

点击清空时:清空所有状态,重置到初始状态。输入输出文本被清空,行数统计归零。

点击复制时:不改变业务状态,只显示操作反馈提示。

5.3 用户反馈机制

应用通过 SnackBar 机制向用户提供操作反馈:

  • 输入为空时点击去重:显示"请输入要去重的文本"
  • 去重完成后:显示"去重完成:从 X 行减少到 Y 行"
  • 输出为空时点击复制:显示"没有可复制的内容"
  • 复制成功时:显示"已复制到剪贴板"

这种即时反馈机制确保用户随时了解操作的结果和当前状态,提升了应用的可用性。

六、关键代码详解

6.1 去重算法实现

文本去重的核心算法非常简洁,利用了 Set 数据结构的去重特性。主要步骤包括:使用 split 方法按换行符将文本分割为字符串列表;调用 toSet 方法将列表转换为 Set,自动去除重复项;调用 toList 方法将 Set 转换回列表;使用 join 方法用换行符将列表重新连接为一个字符串。

这种实现方式充分利用了 Dart 语言内置的集合操作,代码简洁高效。时间复杂度为 O(n),其中 n 是行数,因为 Set 的插入和查找操作平均都是 O(1) 的。

需要注意的是,Set 去重是精确匹配,只有完全相同的行才会被认为是重复的。如果需要忽略首尾空白、忽略大小写等更灵活的去重方式,需要在去重前对每一行进行预处理。

6.2 输入验证机制

应用在执行去重前会进行输入验证,确保输入不为空。这种前置验证避免了无意义的计算,同时给用户明确的提示。验证失败时通过 ScaffoldMessenger 显示 SnackBar 提示,持续2秒后自动消失。

同样,复制功能也会验证输出是否为空,避免在没有结果的情况下执行复制操作。这种防御性编程的思想很重要,它确保了应用在各种边界情况下都能正确运行。

6.3 双控制器模式

应用使用两个独立的文本控制器分别管理输入和输出:

  • 输入控制器:管理用户输入的文本,可编辑
  • 输出控制器:管理去重后的结果,只读

这种双控制器模式的优势在于:输入和输出的状态完全独立,互不干扰;输出控制器配合 readOnly 属性实现只读效果;便于后续扩展功能。

两个控制器在 dispose 方法中被正确释放,确保资源被回收。这是 Flutter 开发中必须注意的细节,忘记释放控制器是常见的内存泄漏原因之一。

6.4 卡片式布局设计

整个去重组件采用卡片式视觉设计:白色背景、圆角边框、轻微的阴影效果。这种设计营造出悬浮感和层次感,使功能区域与背景清晰分离。

卡片式设计的优点在于:视觉上清晰分区,每个卡片是一个独立的功能单元;阴影和圆角营造质感,提升应用的品质感;响应式布局友好;符合 Material Design 的设计语言。

七、技术总结

7.1 技术亮点

简洁高效的去重算法:利用 Dart 内置的 Set 数据结构实现去重,代码简洁,性能高效。充分利用了语言的内置能力,避免了手动实现去重逻辑的复杂性。

清晰的界面布局:界面分为输入、操作、输出和说明四个区域,结构清晰,操作流程符合用户直觉。输入区和输出区采用对称设计,视觉上平衡美观。

完善的用户反馈:通过 SnackBar 机制提供即时的操作反馈,用户可以清楚地知道每次操作的结果。空输入、成功去重、空复制、复制成功等各种情况都有对应的提示。

良好的用户体验细节:只读的输出框避免用户误操作、绿色的输出行数与灰色的输入行数形成视觉区分、使用说明帮助新用户快速上手。

7.2 可优化点

实时去重:当前需要点击按钮才执行去重,可以增加实时去重选项,用户输入时自动显示去重结果。

高级去重选项:忽略大小写去重、忽略首尾空白去重、去除空白行、自定义分隔符、支持正则表达式匹配去重等。

剪贴板集成:当前复制功能是模拟的,可以接入 Flutter 的剪贴板 API 实现真正的复制功能。

结果导出:支持将去重结果保存为文件或分享到其他应用。

性能优化:对于超大量的文本,可以考虑使用异步处理和进度提示,避免界面卡顿。

7.3 技术价值

本项目展示了如何使用 Flutter 开发一个完整的文本处理工具,涉及文本输入与展示、集合操作、用户交互反馈、布局设计等多个方面。对于学习 Flutter 的开发者来说,这是一个很好的实战练习项目。

特别是利用 Set 进行去重的实现方式,展示了合理选择数据结构的重要性。选择合适的数据结构可以大大简化代码,提高效率。这也是编程中的一项重要思维方式:不是所有功能都需要自己从头实现,很多时候语言和标准库已经提供了高效的解决方案。

项目针对 OpenHarmony 平台的适配也展示了 Flutter 跨平台开发的能力,一套代码可以在不同平台上运行,为开发者提供了极大的便利。

请添加图片描述

Flutter for OpenHarmony 实战:文本去重​ - 去除重复行

目录

前言:跨生态开发的新机遇

在移动开发领域,我们总是面临着选择与适配。今天,你的Flutter应用在Android和iOS上跑得正欢,明天可能就需要考虑一个新的平台:HarmonyOS(鸿蒙)。这不是一道选答题,而是很多团队正在面对的现实。

Flutter的优势很明确——写一套代码,就能在两个主要平台上运行,开发体验流畅。而鸿蒙代表的是下一个时代的互联生态,它不仅仅是手机系统,更着眼于未来全场景的体验。将现有的Flutter应用适配到鸿蒙,听起来像是一个“跨界”任务,但它本质上是一次有价值的技术拓展:让产品触达更多用户,也让技术栈覆盖更广。

不过,这条路走起来并不像听起来那么简单。Flutter和鸿蒙,从底层的架构到上层的工具链,都有着各自的设计逻辑。会遇到一些具体的问题:代码如何组织?原有的功能在鸿蒙上如何实现?那些平台特有的能力该怎么调用?更实际的是,从编译打包到上架部署,整个流程都需要重新摸索。
这篇文章想做的,就是把这些我们趟过的路、踩过的坑,清晰地摊开给你看。我们不会只停留在“怎么做”,还会聊到“为什么得这么做”,以及“如果出了问题该往哪想”。这更像是一份实战笔记,源自真实的项目经验,聚焦于那些真正卡住过我们的环节。

无论你是在为一个成熟产品寻找新的落地平台,还是从一开始就希望构建能面向多端的应用,这里的思路和解决方案都能提供直接的参考。理解了两套体系之间的异同,掌握了关键的衔接技术,不仅能完成这次迁移,更能积累起应对未来技术变化的能力。

混合工程结构深度解析

项目目录架构

当Flutter项目集成鸿蒙支持后,典型的项目结构会发生显著变化。以下是经过ohos_flutter插件初始化后的项目结构:

my_flutter_harmony_app/
├── lib/                          # Flutter业务代码(基本不变)
│   ├── main.dart                 # 应用入口
│   ├── home_page.dart           # 首页
│   └── utils/
│       └── platform_utils.dart  # 平台工具类
├── pubspec.yaml                  # Flutter依赖配置
├── ohos/                         # 鸿蒙原生层(核心适配区)
│   ├── entry/                    # 主模块
│   │   └── src/main/
│   │       ├── ets/              # ArkTS代码
│   │       │   ├── MainAbility/
│   │       │   │   ├── MainAbility.ts       # 主Ability
│   │       │   │   └── MainAbilityContext.ts
│   │       │   └── pages/
│   │       │       ├── Index.ets           # 主页面
│   │       │       └── Splash.ets          # 启动页
│   │       ├── resources/        # 鸿蒙资源文件
│   │       │   ├── base/
│   │       │   │   ├── element/  # 字符串等
│   │       │   │   ├── media/    # 图片资源
│   │       │   │   └── profile/  # 配置文件
│   │       │   └── en_US/        # 英文资源
│   │       └── config.json       # 应用核心配置
│   ├── ohos_test/               # 测试模块
│   ├── build-profile.json5      # 构建配置
│   └── oh-package.json5         # 鸿蒙依赖管理
└── README.md

展示效果图片

flutter 实时预览 效果展示

运行到鸿蒙虚拟设备中效果展示

功能代码实现

项目结构调整

在本次开发中,我们首先对项目结构进行了调整,创建了专门的组件目录来存放文本去重功能的实现:

lib/
├── main.dart                 # 应用入口
└── components/
    └── text_duplicate_remover.dart  # 文本去重组件

TextDuplicateRemover 组件开发

组件结构设计

TextDuplicateRemover 是本次开发的核心组件,负责实现文本输入、去重处理和结果展示的完整流程。该组件采用了 StatefulWidget 来管理状态,确保用户交互能够实时反映到界面上。

核心功能实现

以下是 TextDuplicateRemover 组件的核心代码实现:

import 'package:flutter/material.dart';

class TextDuplicateRemover extends StatefulWidget {
  const TextDuplicateRemover({Key? key}) : super(key: key);

  
  _TextDuplicateRemoverState createState() => _TextDuplicateRemoverState();
}

class _TextDuplicateRemoverState extends State<TextDuplicateRemover> {
  final TextEditingController _inputController = TextEditingController();
  final TextEditingController _outputController = TextEditingController();
  int _originalLineCount = 0;
  int _uniqueLineCount = 0;

  void _removeDuplicates() {
    final inputText = _inputController.text;
    if (inputText.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('请输入要去重的文本'),
          duration: Duration(seconds: 2),
        ),
      );
      return;
    }

    // 分割文本为行
    final lines = inputText.split('\n');
    _originalLineCount = lines.length;

    // 使用 Set 去重
    final uniqueLines = lines.toSet().toList();
    _uniqueLineCount = uniqueLines.length;

    // 重新组合为文本
    final outputText = uniqueLines.join('\n');
    _outputController.text = outputText;

    // 显示去重结果提示
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('去重完成:从 $_originalLineCount 行减少到 $_uniqueLineCount 行'),
        duration: Duration(seconds: 2),
      ),
    );
  }

  void _clearInput() {
    _inputController.clear();
    _outputController.clear();
    _originalLineCount = 0;
    _uniqueLineCount = 0;
  }

  void _copyToClipboard() {
    if (_outputController.text.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('没有可复制的内容'),
          duration: Duration(seconds: 2),
        ),
      );
      return;
    }

    // 这里简化处理,实际应用中应该使用 Clipboard 类
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('已复制到剪贴板'),
        duration: Duration(seconds: 2),
      ),
    );
  }

  
  void dispose() {
    _inputController.dispose();
    _outputController.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        boxShadow: [
          BoxShadow(
            color: Colors.grey.withOpacity(0.1),
            spreadRadius: 1,
            blurRadius: 3,
            offset: const Offset(0, 1),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          const Text(
            '文本去重',
            style: TextStyle(
              fontSize: 18,
              fontWeight: FontWeight.w600,
              color: Colors.black87,
            ),
          ),
          const SizedBox(height: 16),

          // 输入区域
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                '输入文本',
                style: TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w500,
                  color: Colors.black87,
                ),
              ),
              const SizedBox(height: 8),
              Container(
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey.withOpacity(0.3)),
                  borderRadius: BorderRadius.circular(6),
                ),
                child: TextField(
                  controller: _inputController,
                  maxLines: 6,
                  decoration: const InputDecoration(
                    hintText: '请输入多行文本,每行一条...',
                    border: InputBorder.none,
                    contentPadding: EdgeInsets.all(12),
                  ),
                  style: const TextStyle(fontSize: 14),
                ),
              ),
              const SizedBox(height: 8),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    '行数: $_originalLineCount',
                    style: const TextStyle(
                      color: Colors.grey,
                      fontSize: 12,
                    ),
                  ),
                  ElevatedButton.icon(
                    onPressed: _clearInput,
                    icon: const Icon(Icons.clear, size: 16),
                    label: const Text('清空'),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.grey[100],
                      foregroundColor: Colors.deepPurple,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(6),
                      ),
                      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
                    ),
                  ),
                ],
              ),
            ],
          ),

          const SizedBox(height: 20),

          // 操作按钮
          Center(
            child: ElevatedButton.icon(
              onPressed: _removeDuplicates,
              icon: const Icon(Icons.filter_list),
              label: const Text('去除重复行'),
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.deepPurple,
                foregroundColor: Colors.white,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
                padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
              ),
            ),
          ),

          const SizedBox(height: 20),

          // 输出区域
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                '去重结果',
                style: TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w500,
                  color: Colors.black87,
                ),
              ),
              const SizedBox(height: 8),
              Container(
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey.withOpacity(0.3)),
                  borderRadius: BorderRadius.circular(6),
                ),
                child: TextField(
                  controller: _outputController,
                  maxLines: 6,
                  readOnly: true,
                  decoration: const InputDecoration(
                    border: InputBorder.none,
                    contentPadding: EdgeInsets.all(12),
                  ),
                  style: const TextStyle(fontSize: 14),
                ),
              ),
              const SizedBox(height: 8),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    '行数: $_uniqueLineCount',
                    style: const TextStyle(
                      color: Colors.green,
                      fontSize: 12,
                    ),
                  ),
                  ElevatedButton.icon(
                    onPressed: _copyToClipboard,
                    icon: const Icon(Icons.copy, size: 16),
                    label: const Text('复制'),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.grey[100],
                      foregroundColor: Colors.deepPurple,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(6),
                      ),
                      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
                    ),
                  ),
                ],
              ),
            ],
          ),

          const SizedBox(height: 16),

          // 说明文本
          Container(
            padding: const EdgeInsets.all(12),
            decoration: BoxDecoration(
              color: Colors.deepPurple[50],
              borderRadius: BorderRadius.circular(6),
            ),
            child: const Text(
              '说明:\n1. 输入多行文本,每行一条\n2. 点击"去除重复行"按钮进行去重\n3. 去重结果会显示在下方\n4. 可以复制去重后的结果',
              style: TextStyle(
                color: Colors.deepPurple,
                fontSize: 12,
                height: 1.5,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

应用入口集成

main.dart 文件中,我们集成了 TextDuplicateRemover 组件,构建了完整的应用界面:

import 'package:flutter/material.dart';
import 'components/text_duplicate_remover.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter for openHarmony',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      debugShowCheckedModeBanner: false,
      home: const MyHomePage(title: 'Flutter for openHarmony'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('文本去重工具'),
        backgroundColor: Colors.deepPurple,
        foregroundColor: Colors.white,
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            TextDuplicateRemover(),
          ],
        ),
      ),
    );
  }
}

核心功能说明

  1. 文本输入与管理

    • 使用 TextEditingController 管理输入和输出文本
    • 支持多行文本输入,每行作为一个独立的条目
    • 实时显示输入文本的行数
  2. 去重算法实现

    • 使用 Set 数据结构进行高效去重
    • 时间复杂度接近 O(n),适用于处理较大规模的文本
    • 保留原始文本的顺序(通过先转为 Set 去重,再转回 List)
  3. 用户交互反馈

    • 提供清空输入、去除重复行、复制结果等操作
    • 使用 SnackBar 显示操作结果和提示信息
    • 实时更新去重前后的行数统计
  4. 界面设计与布局

    • 采用卡片式设计,提供清晰的视觉层次
    • 响应式布局,适配不同屏幕尺寸
    • 合理的间距和边框,提升用户体验

使用方法

  1. 启动应用

    • 运行应用后,会直接进入文本去重工具的主界面
  2. 输入文本

    • 在"输入文本"区域输入要去重的多行文本,每行一条
    • 可以看到实时更新的行数统计
  3. 执行去重

    • 点击"去除重复行"按钮,系统会自动处理文本
    • 处理完成后会显示去重结果和统计信息
  4. 查看结果

    • 去重后的文本会显示在"去重结果"区域
    • 可以看到去重后的行数统计
  5. 复制结果

    • 点击"复制"按钮,可以将去重后的文本复制到剪贴板
  6. 清空输入

    • 点击"清空"按钮,可以清空所有输入和输出内容

本次开发中容易遇到的问题

1. TextStyle 参数错误

问题描述:在开发过程中,使用了 lineHeight 参数设置文本行高,但编译时出现错误。

错误信息

lib/components/text_duplicate_remover.dart:264:17: Error: No named parameter with the name 'lineHeight'. 
                 lineHeight: 1.5, 
                 ^^^^^^^^^^ 
 ../flutter_flutter/packages/flutter/lib/src/painting/text_style.dart:482:9: Context: Found this candidate, but the arguments don't match. 
   const TextStyle({

解决方案:将 lineHeight 参数改为 height 参数,这是 Flutter 中正确的行高设置参数。

修改前

style: TextStyle(
  color: Colors.deepPurple,
  fontSize: 12,
  lineHeight: 1.5,
),

修改后

style: TextStyle(
  color: Colors.deepPurple,
  fontSize: 12,
  height: 1.5,
),

2. 状态管理问题

问题描述:在处理文本去重时,需要实时更新界面状态,但如果状态管理不当,可能导致界面不更新。

解决方案

  • 使用 StatefulWidget 管理组件状态
  • 调用 setState() 方法更新状态,触发界面重建
  • 确保所有状态变量都在 setState() 中更新

3. 用户输入验证

问题描述:用户可能会在未输入文本的情况下点击去重按钮,导致操作无效。

解决方案

  • 在执行去重操作前,检查输入文本是否为空
  • 为空时显示提示信息,避免无效操作
  • 提供清晰的用户反馈,引导用户正确操作

4. 内存管理

问题描述TextEditingController 如果不及时释放,可能导致内存泄漏。

解决方案

  • dispose() 方法中调用 controller.dispose() 释放资源
  • 确保所有控制器都被正确管理

5. 平台适配问题

问题描述:在不同平台上,文本处理和剪贴板操作可能有差异。

解决方案

  • 使用 Flutter 提供的跨平台 API
  • 针对不同平台的特性进行适当的适配
  • 测试在不同平台上的运行效果

总结本次开发中用到的技术点

1. Flutter 基础组件

  • StatefulWidget:用于管理需要动态更新的界面状态
  • TextField:用于文本输入和显示
  • ElevatedButton:用于用户操作按钮
  • Container:用于布局和样式设置
  • Row/Column:用于线性布局
  • SnackBar:用于显示临时消息和反馈

2. 状态管理

  • setState():用于更新组件状态,触发界面重建
  • TextEditingController:用于管理文本输入和输出
  • 生命周期管理:使用 initState()dispose() 方法管理资源

3. 文本处理算法

  • Set 去重:利用 Set 数据结构的特性进行高效去重
  • 字符串操作:使用 split()join() 方法处理文本行
  • 列表操作:使用 toSet()toList() 方法转换数据结构

4. 用户界面设计

  • 卡片式设计:使用 BoxDecoration 创建卡片效果
  • 响应式布局:使用 SingleChildScrollView 适配不同屏幕
  • 视觉层次:通过颜色、间距、边框等元素创建清晰的视觉层次
  • 用户反馈:提供即时、清晰的操作反馈

5. 错误处理与调试

  • 参数错误处理:正确使用 Flutter API,避免参数错误
  • 用户输入验证:对用户输入进行合理的验证和提示
  • 资源管理:正确管理控制器等资源,避免内存泄漏
  • 编译错误修复:及时修复编译错误,确保代码质量

6. 鸿蒙平台适配

  • 项目结构调整:按照鸿蒙项目要求组织代码结构
  • 跨平台兼容性:确保代码在鸿蒙平台上正常运行
  • 性能优化:考虑鸿蒙平台的性能特性,进行适当优化

7. 开发最佳实践

  • 组件化开发:将功能封装为独立组件,提高代码复用性
  • 代码可读性:使用清晰的命名和注释,提高代码可读性
  • 用户体验:注重界面设计和交互体验,提供直观的操作方式
  • 错误处理:完善的错误处理机制,提升应用稳定性

通过本次开发,我们不仅实现了一个实用的文本去重工具,还积累了在 Flutter for OpenHarmony 平台上开发应用的经验。这些技术点和最佳实践,对于后续开发类似应用或进行更复杂的项目,都具有参考价值。

请添加图片描述

flutter_openHarmony(简称 Flutter‑OH)

注意:不是Google官方产物,是OpenHarmony社区TPC组织维护的Flutter引擎移植版本。把Flutter的Dart/Skia引擎做底层改造,让Flutter应用可以直接编译输出 HAP包,跑在OpenHarmony/纯血鸿蒙设备上,不需要依赖Android兼容层。

简单讲:一套Dart/Flutter业务代码,可以同时编译 Android、iOS、OpenHarmony(HAP)

核心原理

对Flutter Engine做Embedder嵌入适配,对接OpenHarmony Rosen图形管线、UIAbility生命周期,通过MethodChannel实现 Dart ↔ ArkTS双向通信,Flutter自绘UI渲染到鸿蒙Surface,复用方舟编译器、系统权限、分布式能力。

  • Dart业务代码几乎不变
  • 底层引擎适配鸿蒙图形、线程、生命周期
  • 输出产物是标准HAP应用包,可上架鸿蒙应用市场

主要优势

  1. 存量Flutter项目低成本接入鸿蒙生态
    纯Dart业务、纯Widget界面几乎不用改代码即可编译出鸿蒙HAP;只有带Android/iOS原生桥接的插件,才需要做鸿蒙适配替换。已经有成熟Flutter App,想快速覆盖鸿蒙设备,不用全部重写ArkTS。

  2. 多端UI高度一致性
    Flutter自绘渲染,不受各平台控件差异影响,手机、平板、车机界面表现统一;滚动、动画、首页各类动效(轮播、吸顶、骨架屏、入场动画)跨平台表现一致,和你前面问的App首页各种效果可以一套代码全部实现。

  3. 继承Flutter完整开发体验
    保留热重载、DevTools调试、完整Widget组件库;pub.dev海量纯Dart三方库直接复用,是鸿蒙跨端方案里三方库最丰富的方案。提供定制CLI,一条命令完成编译、真机调试、打包HAP。

  4. 可调用OpenHarmony原生系统能力
    支持调用分布式软总线、分布式数据KV、原子化服务、鸿蒙权限体系、硬件能力;Flutter页面和ArkTS原生页面可以混合开发、互相跳转,复杂原生逻辑继续写ArkTS,UI业务交给Flutter实现。

  5. 全场景设备覆盖
    支持OpenHarmony手机、平板、智慧屏、车机等设备,适合需要多终端统一UI的业务。引擎做了懒加载,跟随UIAbility生命周期启停,控制内存占用,减少后台资源消耗。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐