You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中使用flutter_quill显示与编辑HTML内容

Flutter集成flutter_quill实现HTML富文本编辑与渲染方案

问题描述

在Flutter应用中集成flutter_quill: ^9.5.3时遇到以下需求与问题:

  • 从后端接收带HTML标签的字符串,需要正确渲染HTML格式内容
  • 支持用户友好编辑富文本内容
  • 修改完成后将内容以HTML格式返回后端

当前代码使用普通TextFormField,只能显示原始HTML文本,无法渲染格式,也不支持富文本编辑。

实现方案(基于flutter_quill: ^9.5.3)

flutter_quill支持HTML与Quill Delta格式的双向转换,完全匹配需求。以下是改造后的完整组件代码:

1. 核心依赖确认

确保pubspec.yaml中已添加:

dependencies:
  flutter_quill: ^9.5.3

2. 改造后的组件代码

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

class DescriptionHTMLEditText extends StatefulWidget {
  final String title;
  final String htmlText;
  final Function(String) onChanged;
  final bool isEditable;

  const DescriptionHTMLEditText({
    super.key,
    required this.title,
    required this.htmlText,
    required this.onChanged,
    required this.isEditable,
  });

  @override
  State<DescriptionHTMLEditText> createState() =>
      _DescriptionHTMLEditTextState();
}

class _DescriptionHTMLEditTextState extends State<DescriptionHTMLEditText> {
  bool _isEditing = false;
  late QuillController _quillController;

  @override
  void initState() {
    super.initState();
    // 将后端传入的HTML转换为Quill Delta格式,初始化编辑器
    _quillController = QuillController(
      document: widget.htmlText.isEmpty
          ? Document()
          : Document.fromHtml(widget.htmlText),
      selection: const TextSelection.collapsed(offset: 0),
    );
  }

  @override
  void didUpdateWidget(covariant DescriptionHTMLEditText oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 当外部传入的HTML文本变化时,更新编辑器内容
    if (oldWidget.htmlText != widget.htmlText) {
      _quillController.document = widget.htmlText.isEmpty
          ? Document()
          : Document.fromHtml(widget.htmlText);
    }
  }

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

  // 将Quill内容转换为HTML字符串
  String _convertToHtml() {
    return _quillController.document.toHtml();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              widget.title,
              style: Theme.of(context).textTheme.titleSmall,
            ),
            if (!_isEditing && widget.isEditable)
              TextButton(
                onPressed: () => setState(() => _isEditing = true),
                child: const Text("Modify"),
              )
          ],
        ),
        const SizedBox(height: 8),
        AnimatedSwitcher(
          duration: const Duration(milliseconds: 250),
          child: _isEditing
              ? _buildEditingMode()
              : _buildDisplayMode(),
        ),
      ],
    );
  }

  // 编辑模式:带工具栏的富文本编辑器
  Widget _buildEditingMode() {
    return Column(
      key: const Key('description-editor-editable'),
      children: [
        // 富文本编辑工具栏
        if (widget.isEditable)
          QuillToolbar.basic(
            controller: _quillController,
            showAlignmentButtons: false, // 根据需求调整工具栏按钮
            showBackgroundColorButton: false,
            showColorButton: false,
          ),
        const SizedBox(height: 8),
        // 富文本编辑器
        Container(
          decoration: BoxDecoration(
            border: Border.all(color: Colors.grey.shade300),
            borderRadius: BorderRadius.circular(8),
          ),
          child: QuillEditor.basic(
            controller: _quillController,
            readOnly: false,
            minHeight: 150,
            padding: const EdgeInsets.all(12),
          ),
        ),
        const SizedBox(height: 8),
        Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            TextButton(
              onPressed: () => setState(() => _isEditing = false),
              child: const Text("Cancel"),
            ),
            const SizedBox(width: 8),
            ElevatedButton(
              onPressed: () {
                setState(() => _isEditing = false);
                widget.onChanged(_convertToHtml());
              },
              child: const Text("Save"),
            ),
          ],
        ),
      ],
    );
  }

  // 显示模式:只读渲染富文本内容
  Widget _buildDisplayMode() {
    return widget.htmlText.isEmpty
        ? const Text("No description available", style: TextStyle(color: Colors.grey))
        : Container(
            padding: const EdgeInsets.all(12),
            decoration: BoxDecoration(
              color: Colors.grey.shade50,
              borderRadius: BorderRadius.circular(8),
            ),
            child: QuillEditor.basic(
              controller: _quillController,
              readOnly: true,
              minHeight: 100,
            ),
          );
  }
}

3. 关键功能说明

  • HTML转Quill内容:通过Document.fromHtml(widget.htmlText)将后端HTML字符串转换为Quill可编辑的Delta格式
  • Quill内容转HTML:通过_quillController.document.toHtml()将编辑后的富文本转换回HTML,提交给后端
  • 渲染与编辑切换:使用AnimatedSwitcher实现显示模式(只读Quill编辑器,自动渲染格式)和编辑模式(带工具栏的可编辑编辑器)的平滑切换
  • 状态同步:通过didUpdateWidget监听外部传入的HTML变化,确保编辑器内容与后端数据同步

4. 自定义调整建议

  • 工具栏按钮:通过QuillToolbar.basic的参数(如showBoldButton、showItalicButton等)自定义显示的编辑工具
  • 编辑器样式:修改QuillEditor.basic的padding、decoration等属性匹配你的应用主题
  • 空内容处理:可根据需求自定义空状态的显示样式

内容的提问来源于stack exchange,提问作者MICHEL Baptiste

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:32:15