Flutter Quill 富文本编辑器:从入门到精通

Flutter Quill 富文本编辑器:从入门到精通

【免费下载链接】flutter-quill Rich text editor for Flutter 【免费下载链接】flutter-quill 项目地址: https://gitcode.com/gh_mirrors/fl/flutter-quill

Flutter Quill 是一个专为 Flutter 设计的富文本编辑器组件,适用于现代的 Android、iOS、Web 以及桌面平台。该编辑器提供了一个直观的 WYSIWYG(所见即所得)界面,让用户能够轻松创作含有编号列表、项目符号列表、超链接等丰富格式的长篇文章。

项目安装与配置

环境要求

确保你的开发环境已经配置好 Flutter,然后创建一个新的 Flutter 项目:

flutter create my_text_editor_app
cd my_text_editor_app

添加依赖

将 Flutter Quill 添加到你的 pubspec.yaml 文件中:

dependencies:
  flutter:
    sdk: flutter
  flutter_quill: ^latest_version

替换 latest_version 为你实际查找得到的最新版本号。之后,运行 flutter pub get 来安装依赖。

平台特定配置

对于 Android 平台,需要配置以下内容以支持图像复制到剪贴板:

1. 更新 AndroidManifest.xml

android/app/src/main/AndroidManifest.xml<application> 标签内添加:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

2. 创建 file_paths.xml

创建文件 android/app/src/main/res/xml/file_paths.xml 并添加以下内容:

<paths>
    <cache-path name="cache" path="." />
</paths>

基础使用教程

初始化应用

lib/main.dart 中,初始化并使用 Flutter Quill:

import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

void main() => runApp(const MainApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.light(useMaterial3: true),
      darkTheme: ThemeData.dark(useMaterial3: true),
      themeMode: ThemeMode.system,
      home: HomePage(),
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        FlutterQuillLocalizations.delegate,
      ],
    );
  }
}

创建控制器和界面

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final QuillController _controller = () {
    return QuillController.basic(
      config: QuillControllerConfig(
        clipboardConfig: QuillClipboardConfig(
          enableExternalRichPaste: true,
          onImagePaste: (imageBytes) async {
    if (kIsWeb) {
      return null;
    }
    final newFileName = 'image-file-${DateTime.now().toIso8601String()}.png';
    final newPath = path.join(
      io.Directory.systemTemp.path,
      newFileName,
    );
    final file = await io.File(
      newPath,
    ).writeAsBytes(imageBytes, flush: true);
    return file.path;
    },
    ),
  );
  }();
  final FocusNode _editorFocusNode = FocusNode();
  final ScrollController _editorScrollController = ScrollController();

  @override
  void initState() {
    super.initState();
    _controller.document = Document.fromJson(kQuillDefaultSample);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Quill Example'),
        actions: [
          IconButton(
            icon: const Icon(Icons.output),
            tooltip: 'Print Delta JSON to log',
            onPressed: () {
              debugPrint(jsonEncode(_controller.document.toDelta().toJson()));
            },
          ),
        ],
      ),
      body: SafeArea(
        child: Column(
          children: [
            QuillSimpleToolbar(
              controller: _controller,
              config: QuillSimpleToolbarConfig(
                embedButtons: FlutterQuillEmbeds.toolbarButtons(),
                showClipboardPaste: true,
                customButtons: [
                  QuillToolbarCustomButtonOptions(
                    icon: const Icon(Icons.add_alarm_rounded),
                    onPressed: () {
                      _controller.document.insert(
                        _controller.selection.extentOffset,
                        TimeStampEmbed(
                          DateTime.now().toString(),
                        ),
                      );
                      _controller.updateSelection(
                        TextSelection.collapsed(
                          offset: _controller.selection.extentOffset + 1,
                        ),
                        ChangeSource.local,
                      );
                    },
                  ),
                ],
                buttonOptions: QuillSimpleToolbarButtonOptions(
                  base: QuillToolbarBaseButtonOptions(
                    afterButtonPressed: () {
                      final isDesktop = {
                        TargetPlatform.linux,
                        TargetPlatform.windows,
                        TargetPlatform.macOS
                      }.contains(defaultTargetPlatform);
                      if (isDesktop) {
                        _editorFocusNode.requestFocus();
                      }
                    },
                  ),
                  linkStyle: QuillToolbarLinkStyleButtonOptions(
                    validateLink: (link) {
                      return true;
                    },
                  ),
                ),
              ),
            ),
            Expanded(
              child: QuillEditor(
                focusNode: _editorFocusNode,
                scrollController: _editorScrollController,
                controller: _controller,
                config: QuillEditorConfig(
                  placeholder: 'Start writing your notes...',
                  padding: const EdgeInsets.all(16),
                  embedBuilders: [
                    ...FlutterQuillEmbeds.editorBuilders(
                      imageEmbedConfig: QuillEditorImageEmbedConfig(
                        imageProviderBuilder: (context, imageUrl) {
                          if (imageUrl.startsWith('assets/')) {
                            return AssetImage(imageUrl);
                          }
                          return null;
                        },
                      ),
                      videoEmbedConfig: QuillEditorVideoEmbedConfig(
                        customVideoBuilder: (videoUrl, readOnly) {
                          return null;
                        },
                      ),
                    ),
                    TimeStampEmbedBuilder(),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

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

自定义嵌入块

Flutter Quill 提供了自定义嵌入块的接口,允许用户提供自己的实现:

class TimeStampEmbed extends Embeddable {
  const TimeStampEmbed(
    String value,
  ) : super(timeStampType, value);

  static const String timeStampType = 'timeStamp';

  static TimeStampEmbed fromDocument(Document document) =>
      TimeStampEmbed(jsonEncode(document.toDelta().toJson()));

  Document get document => Document.fromJson(jsonDecode(data));
}

class TimeStampEmbedBuilder extends EmbedBuilder {
  @override
  String get key => 'timeStamp';

  @override
  String toPlainText(Embed node) {
    return node.value.data;
  }

  @override
  Widget build(
    BuildContext context,
    EmbedContext embedContext,
  ) {
    return Row(
      children: [
        const Icon(Icons.access_time_rounded),
        Text(embedContext.node.value.data as String),
      ],
    );
  }
}

高级功能与配置

富文本粘贴功能

Flutter Quill 支持从其他应用复制内容并粘贴到编辑器中作为富文本。该功能通过 quill_native_bridge 插件提供对系统剪贴板的访问。

富文本粘贴演示

工具栏自定义配置

QuillSimpleToolbar(
  controller: _controller,
  configurations: QuillSimpleToolbarConfigurations(
    toolbarOptions: ToolbarOptions(
      fonts: ['Arial', 'Times New Roman'],
      formats: [
        'bold', 
        'italic', 
        'underline', 
        'strikeThrough', 
        'header', 
        'list', 
        'bullet'
      ],
    ),
  ),
),

数据输入输出

Flutter Quill 使用 Quill Delta 格式来表示文档内容。Delta 格式是一种紧凑而多功能的方法,通过一系列表示插入、删除或格式更改的操作来描述文档更改。

保存文档:

final String json = jsonEncode(_controller.document.toDelta().toJson());

加载文档:

final String json = ...; // 加载先前存储的 JSON Quill Delta
_controller.document = Document.fromJson(jsonDecode(json));

更改只读模式:

_controller.readOnly = true; // 或 false 允许编辑

实际应用案例

编辑器界面截图

iOS 示例应用截图

Web 示例应用截图

自定义字体配置

要使用自己的字体,需要更新你的资源目录并将 items 传递给 QuillToolbarFontFamilyButton 的选项。确保正确配置字体文件路径和字体族名称。

最佳实践建议

  1. 控制器管理:始终在 dispose 方法中正确释放控制器资源
  2. 文档存储:建议将文档存储为 Delta JSON 格式而非其他格式
  3. 平台适配:针对不同平台进行适当的配置和测试
  4. 性能优化:对于大型文档,考虑使用分页加载或虚拟滚动

注意事项

  • 目前富文本粘贴功能在 Web 平台上暂不支持
  • 从 Delta 转换到 HTML 不是标准功能,建议谨慎使用
  • 存储 Delta 作为 HTML 在数据库中,然后在加载文档时将其转换回 Delta 是不推荐的

通过遵循本指南,你将能够快速上手 Flutter Quill 并构建功能强大的富文本编辑应用。该库提供了丰富的定制选项,可以满足各种复杂的文本编辑需求。

【免费下载链接】flutter-quill Rich text editor for Flutter 【免费下载链接】flutter-quill 项目地址: https://gitcode.com/gh_mirrors/fl/flutter-quill

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值