Flutter富文本编辑器插件lucy_editor的使用

Flutter富文本编辑器插件lucy_editor的使用

Lucy_Editor 是一个功能强大的轻量级文本和代码编辑器小部件,是 Reqable 项目的一个模块。它可以用于简单的文本区域,也可以开发具有复杂功能的代码编辑器。与 Flutter 的默认 TextField 组件不同,Lucy_Editor 特别适用于多行文本的显示和输入,并提供了以下功能:

  • 双向水平和垂直滚动。
  • 文本语法高亮。
  • 内容折叠和展开。
  • 输入提示和自动完成。
  • 搜索和替换。
  • 自定义上下文菜单构建器。
  • 快捷键。
  • 大文本显示和编辑。
  • 行号和焦点行构建。
  • 智能输入。
  • 提高性能。
  • 支持 Javascript AST。
  • 更复杂的 Javascript 自动完成。

Lucy_Editor 不是基于 TextField 的二次封装,而是独立实现了布局、绘制和事件处理等功能。它特别优化了大文本的处理,提供了极高的性能,并修复了 TextField 的一些问题。

Lucy_Editor 提供了高度的自由度。例如,开发者可以控制是否启用水平滚动(换行),是否启用只读模式,是否显示行号,是否显示内容折叠,定义自定义快捷键,并指定文本语法高亮。

你可以运行 example 项目来体验它。

开始使用

pubspec.yaml 中添加以下依赖项:

dependencies:
  lucy_editor: ^1.0.7

TextField 一样,Lucy_Editor 使用 CodeLineEditingController 作为控制器。以下示例代码创建了最简单的编辑组件,与 TextField 没有太大区别。

Widget build(BuildContext context) {
  return CodeEditor(
    controller: CodeLineEditingController.fromText('Hello Reqable'),
  );
}

文本语法高亮

Lucy_Editor 的文本高亮基于 Re-Highlight,支持近百种语言和主题样式。开发者可以自由选择和配置代码高亮。以下代码指定了 JSON 语法高亮规则,并应用了 Atom One Light 代码配色。

CodeEditor(
  style: CodeEditorStyle(
    codeTheme: CodeHighlightTheme(
      languages: {
        'json': CodeHighlightThemeMode(
          mode: langJson
        )
      },
      theme: atomOneLightTheme
    ),
  ),
);

行号和折叠/展开标记

Lucy_Editor 支持配置是否显示代码行号和代码折叠标记,开发者还可以自行实现显示样式和布局。以下示例代码展示了默认样式,使用了 indicatorBuilder

CodeEditor(
  indicatorBuilder: (context, editingController, chunkController, notifier) {
    return Row(
      children: [
        DefaultCodeLineNumber(
          controller: editingController,
          notifier: notifier,
        ),
        DefaultCodeChunkIndicator(
          width: 20,
          controller: chunkController,
          notifier: notifier
        )
      ],
    );
  },
);

代码折叠和展开检测

默认情况下,Lucy_Editor 将自动检测 {}[] 的折叠区域。开发者可以控制是否进行检测或编写自己的检测规则。DefaultCodeChunkAnalyzer 是默认检测器。如果要禁用检测,可以使用 NonCodeChunkAnalyzer

CodeEditor(
  chunkAnalyzer: DefaultCodeChunkAnalyzer(),
);

如果你想自定义检测逻辑,只需实现 CodeChunkAnalyzer 接口。

abstract class CodeChunkAnalyzer {
  List<CodeChunk> run(CodeLines codeLines);
}

滚动控制

Lucy_Editor 支持双向滚动,因此使用两个 ScrollController,开发者可以使用 CodeScrollController 构建。

CodeEditor(
  scrollController: CodeScrollController(
    verticalScroller: ScrollController(),
    horizontalScroller: ScrollController(),
  )
);

查找和替换

Lucy_Editor 实现了查找和替换的控制逻辑,但不提供默认的 UI。开发者需要根据自身项目的实际情况编写查找面板的 UI,并使用 findBuilder 属性设置自己的查找和替换 UI。

CodeEditor(
  findBuilder: (context, controller, readOnly) => CodeFindPanelView(controller: controller, readOnly: readOnly),
);

上面的 CodeFindPanelView 是由开发者自己实现的。详细的实现过程请参阅 example 中的代码。

上下文菜单

Lucy_Editor 实现了桌面上下文菜单和移动长按选择菜单的控制逻辑,但不提供默认的 UI。开发者需要实现 SelectionToolbarController 接口并通过 toolbarController 设置它。

CodeEditor(
  toolbarController: _MyToolbarController(),
);

快捷键

Lucy_Editor 内置了一些默认的快捷键热键,开发者也可以使用 shortcutsActivatorsBuilder 来设置自定义的快捷键。当然,快捷键仅在桌面端有效。

Lucy_Editor 支持的快捷键如下:

  • 全选(Control/Command + A)
  • 剪切当前行/选中内容(Control/Command + X)
  • 复制当前行/选中内容(Control/Command + C)
  • 粘贴(Control/Command + V)
  • 撤销(Control/Command + Z)
  • 重做(Shift + Control/Command + Z)
  • 选中当前行(Control/Command + L)
  • 删除当前行(Control/Command + D)
  • 移动当前行(Alt + ↑/↓)
  • 连续选择(Shift + ↑/↓/←/→)
  • 移动光标(↑/↓/←/→)
  • 移动到页面顶部/底部(Control/Command + ↑/↓)
  • 缩进(Tab)
  • 取消缩进(Shift + Tab)
  • 单行注释/取消注释(Control/Command + /)
  • 多行注释/取消注释(Shift + Control/Command + /)
  • 字符转置(Control/Command + T)
  • 查找(Control/Command + F)
  • 替换(Alt + Control/Command + F)
  • 保存(Control/Command + S)

代码提示和自动完成

Lucy_Editor 支持使用 CodeAutocomplete 组件来实现代码输入提示和自动完成。Lucy_Editor 实现了基本的控制逻辑,但代码提示内容、自动完成规则和显示 UI 需要由开发者定义。

CodeAutocomplete(
  builder: (context, notifier, onSelected) {
    // TODO
  },
  language: langDart,
  child: CodeEditor()
);

请注意,Lucy_Editor 只是一个轻量级的编辑器,并没有 IDE 动态语法分析的功能,所以代码提示和自动完成有很多限制。你可以参考 example 中的代码来实现一个简单的代码提示和完成。

使用示例

以下是完整的示例代码,展示了如何使用 Lucy_Editor 创建一个包含多种功能的编辑器。

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import './editor_autocomplete.dart';
import './editor_basic_field.dart';
import './editor_json.dart';
import './editor_large_text.dart';
import 'editor_javascript.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Re-Editor',
      theme: ThemeData(
        colorScheme: ColorScheme.light(
          primary: Color.fromARGB(255, 255, 140, 0),
        )
      ),
      home: const MyHomePage(title: 'Re-Editor Demo Page'),
    );
  }
}

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

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  static const Map<String, Widget> _editors = {
    'Basic Field': BasicField(),
    'Json Editor': JsonEditor(),
    'Auto Complete': AutoCompleteEditor(),
    'Large Text': LargeTextEditor(),
    'Js Editor': JsEditor(),
  };

  int _index = 0;

  [@override](/user/override)
  Widget build(BuildContext context) {
    final Widget child = _editors.values.elementAt(_index);
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        margin: const EdgeInsets.all(20),
        child: Column(
          children: [
            Row(
              children: _editors.entries.mapIndexed((index, entry) {
                return TextButton(
                  onPressed: () {
                    setState(() {
                      _index = index;
                    });
                  },
                  child: Text(
                    entry.key,
                    style: TextStyle(
                      color: _index == index ? null : Colors.black
                    ),
                  ),
                );
              }).toList(),
            ),
            Expanded(
              child: Container(
                decoration: BoxDecoration(
                  color: Colors.transparent,
                  border: Border.all(
                    color: Colors.grey
                  )
                ),
                child: child,
              )
            )
          ],
        )
      ),
    );
  }
}

更多关于Flutter富文本编辑器插件lucy_editor的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter富文本编辑器插件lucy_editor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用lucy_editor插件的示例代码。lucy_editor是一个功能强大的富文本编辑器插件,适用于需要复杂文本编辑功能的Flutter应用。

步骤1:添加依赖

首先,你需要在你的pubspec.yaml文件中添加lucy_editor的依赖:

dependencies:
  flutter:
    sdk: flutter
  lucy_editor: ^最新版本号  # 请替换为实际发布的最新版本号

步骤2:导入插件

在你的Dart文件中导入lucy_editor

import 'package:lucy_editor/lucy_editor.dart';

步骤3:使用LucyEditor

下面是一个完整的示例,展示如何在Flutter应用中使用LucyEditor

import 'package:flutter/material.dart';
import 'package:lucy_editor/lucy_editor.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('LucyEditor Example'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: LucyEditorScreen(),
        ),
      ),
    );
  }
}

class LucyEditorScreen extends StatefulWidget {
  @override
  _LucyEditorScreenState createState() => _LucyEditorScreenState();
}

class _LucyEditorScreenState extends State<LucyEditorScreen> {
  final LucyController _controller = LucyController();

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Expanded(
          child: LucyEditor(
            controller: _controller,
            initContent: "初始内容",
            placeholder: "在这里输入内容...",
            // 可选参数,根据需求设置
            imageMaxSize: 1024 * 1024, // 图片大小限制(字节)
            textStyle: TextStyle(fontSize: 16), // 默认文本样式
            maxLines: 100, // 最大行数
            // 更多参数请参考文档
          ),
        ),
        SizedBox(height: 16),
        ElevatedButton(
          onPressed: () {
            // 获取编辑器内容
            _controller.getText().then((text) {
              // 处理获取到的文本内容
              print("编辑器内容: $text");
            });
          },
          child: Text("获取内容"),
        ),
      ],
    );
  }
}

解释

  1. 依赖添加:在pubspec.yaml中添加lucy_editor依赖。
  2. 导入插件:在Dart文件中导入lucy_editor包。
  3. 创建LucyEditorScreen:创建一个包含LucyEditor的Widget。
  4. LucyController:使用LucyController来管理编辑器的状态和内容。
  5. 获取编辑器内容:通过_controller.getText()方法获取编辑器中的内容。

注意事项

  • 确保你使用的lucy_editor版本与Flutter SDK兼容。
  • 你可以根据需求进一步配置LucyEditor的参数,例如添加图片、视频支持,自定义工具栏等。
  • 查阅lucy_editor的官方文档,获取更多详细信息和高级用法。

希望这个示例能帮助你快速上手lucy_editor

回到顶部