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

发布于 1周前 作者 caililin 来自 Flutter

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

Re-Editor

latest version

中文版本

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

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

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

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

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

示例动图

入门指南

pubspec.yaml 中添加以下依赖:

dependencies:
  re_editor: ^0.6.0

TextField 一样,Re-Editor 使用 CodeLineEditingController 作为控制器。以下示例代码创建了一个最简单的多行输入区域,与 TextField 差不多。

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

文本语法高亮

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

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

行号和折叠/展开标记

Re-Editor 支持配置是否显示代码行号和代码折叠标记,开发者也可以自行实现显示样式和布局。以下示例代码显示了默认样式,通过 indicatorBuilder 构建。

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

代码折叠和展开检测

默认情况下,Re-Editor 会自动检测 {}[] 的折叠区域。开发者可以控制是否检测或编写自己的检测规则。DefaultCodeChunkAnalyzer 是默认检测器。如果希望禁用检测,可以使用 NonCodeChunkAnalyzer

CodeEditor(
  chunkAnalyzer: DefaultCodeChunkAnalyzer(),
);

如果要自定义,只需实现 CodeChunkAnalyzer 接口。

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

滚动控制

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

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

查找和替换

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

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

上述示例中的 CodeFindPanelView 由开发者自己实现。详细实现过程请参考 example 中的代码。

上下文菜单

Re-Editor 实现了桌面右键菜单和移动设备长按选择菜单的控制逻辑,但不提供默认的 UI。开发者需要实现 SelectionToolbarController 接口并通过 toolbarController 设置。

CodeEditor(
  toolbarController: _MyToolbarController(),
);

快捷键

Re-Editor 内置了默认的快捷键,开发者也可以使用 shortcutsActivatorsBuilder 设置自定义的快捷键。当然,快捷键仅在桌面上生效。

Re-Editor 支持的快捷键如下:

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

代码提示和自动完成

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

CodeAutocomplete(
  viewBuilder: (context, notifier, onSelected) {
    // 构建代码提示视图
  },
  promptsBuilder: DefaultCodeAutocompletePromptsBuilder(
    language: langDart,
  ),
  child: CodeEditor()
);

请注意,Re-Editor 仅是一个轻量级编辑器,没有 IDE 动态语法分析,因此代码提示和完成有很多限制。你可以参考 example 中的代码实现简单的代码提示和完成。

应用实例

Re-Editor 在 Reqable 项目中得到了广泛实践。欢迎下载 Reqable 体验它。

示例图片

许可证

MIT License

赞助

如果你愿意赞助这个项目,可以通过购买 Reqable 许可来支持我们。

示例代码

以下是一个完整的示例代码,展示了如何在 Flutter 项目中使用 Re-Editor

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Re-Editor',
      theme: ThemeData(
        colorScheme: const 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
  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(),
  };

  int _index = 0;

  @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: [
            SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: 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(
                  border: Border.all(
                    color: Colors.grey
                  )
                ),
                child: child,
              )
            )
          ],
        )
      ),
    );
  }
}

希望这个示例对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。


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

1 回复

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


当然,下面是一个关于如何使用Flutter中的re_editor富文本编辑器插件的示例代码。这个插件允许你在Flutter应用中实现富文本编辑功能。

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

dependencies:
  flutter:
    sdk: flutter
  re_editor: ^latest_version  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来,你可以在你的Flutter应用中创建一个简单的富文本编辑器。以下是一个完整的示例代码:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter RE Editor Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late ReEditorController _controller;

  @override
  void initState() {
    super.initState();
    _controller = ReEditorController(
      initialText: 'Hello, this is a rich text editor demo!',
      initialSelection: TextSelection.collapsed(offset: 0),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter RE Editor Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: <Widget>[
            Expanded(
              child: ReEditor(
                controller: _controller,
                focusNode: FocusNode(),
                toolbarOptions: ReToolbarOptions(
                  backgroundColor: Colors.grey[200],
                  iconColor: Colors.black,
                  iconSelectedColor: Colors.blue,
                ),
                onTextChanged: (text) {
                  print('Text changed: $text');
                },
                onSelectionChanged: (selection) {
                  print('Selection changed: $selection');
                },
              ),
            ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  // 获取富文本内容
                  final document = _controller.document;
                  // 打印或处理document
                  print(document.toPlainText());
                });
              },
              child: Text('Get Text'),
            ),
          ],
        ),
      ),
    );
  }
}

代码解释

  1. 依赖导入: 在pubspec.yaml中添加re_editor依赖。

  2. 应用结构: 创建一个简单的Flutter应用,包含一个主页面MyHomePage

  3. 控制器初始化: 在_MyHomePageStateinitState方法中初始化ReEditorController,并设置初始文本和选择范围。

  4. UI布局: 使用Column布局包含一个扩展的ReEditor和一个按钮。ReEditor用于显示和编辑富文本,按钮用于获取当前富文本内容。

  5. 工具栏选项: 使用ReToolbarOptions自定义工具栏的背景色、图标色和选中图标色。

  6. 事件监听: 监听文本变化和选择变化事件,并打印出变化的内容。

  7. 获取文本: 点击按钮时,获取当前富文本内容并打印。

请确保你已经安装了最新版本的re_editor插件,并根据需要调整代码。希望这个示例能帮助你快速上手re_editor富文本编辑器插件!

回到顶部