Flutter自定义HTML编辑器插件custom_quill_html_editor的使用
Flutter 自定义 HTML 编辑器插件 custom_quill_html_editor 的使用
Quill Html Editor 是一个为 Android、iOS 和 Web 平台设计的强大 HTML 富文本编辑器。它利用了 QuillJs 库的功能,提供了一个功能丰富的现代 Web 应用编辑体验。
特性
- 高度可定制化的 编辑器 和 工具栏 小部件。
- 支持 Delta 格式,允许你使用
setDelta
和getDelta
方法设置和检索内容。 - 支持无缝复制粘贴富文本。
- 可分离的工具栏可以放置在页面的任何位置。
- 提供了添加自定义按钮到工具栏的灵活性。
- 支持插入图像、视频和表格。
- 允许以 HTML 和 Delta 格式设置和检索文本。
- 支持集成 Google 字体以获得广泛的字体选项。
演示
要体验 Quill Html Editor 的功能,你可以访问我们的 演示页面。探索编辑器的各种功能,并查看如何增强你的 Web 编辑体验。
截图
文档
详情请参阅以下文档:
使用方法
首先,定义一个 QuillEditorController
以访问编辑器的方法,并将其传递给 QuillHtmlEditor
组件。
final QuillEditorController controller = QuillEditorController();
QuillHtmlEditor(
text: "<h1>Hello</h1>This is a quill html editor example 😊",
hintText: 'Hint text goes here',
controller: controller,
isEnabled: true,
minHeight: 300,
textStyle: _editorTextStyle,
hintTextStyle: _hintTextStyle,
hintTextAlign: TextAlign.start,
padding: const EdgeInsets.only(left: 10, top: 5),
hintTextPadding: EdgeInsets.zero,
backgroundColor: _backgroundColor,
onFocusChanged: (hasFocus) => debugPrint('has focus $hasFocus'),
onTextChanged: (text) => debugPrint('widget text change $text'),
onEditorCreated: () => debugPrint('Editor has been loaded'),
onEditingComplete: (s) => debugPrint('Editing completed $s'),
onEditorResized: (height) =>
debugPrint('Editor resized $height'),
onSelectionChanged: (sel) =>
debugPrint('${sel.index},${sel.length}'),
loadingBuilder: (context) {
return const Center(
child: CircularProgressIndicator(
strokeWidth: 0.4,
));
},
)
接下来,定义一个 ToolBar
小部件并传递相同的 controller
。
ToolBar(
toolBarColor: Colors.cyan.shade50,
activeIconColor: Colors.green,
padding: const EdgeInsets.all(8),
iconSize: 20,
controller: controller,
customButtons: [
InkWell(onTap: () {}, child: const Icon(Icons.favorite)),
InkWell(onTap: () {}, child: const Icon(Icons.add_circle)),
],
)
工具栏滚动配置
ToolBar.scroll
小部件允许你将工具栏按钮显示在单行或单列中,这取决于指定的 direction
参数。默认情况下,direction
设置为 Axis.horizontal
,这将按钮排列在一行中。
要更改方向并将按钮显示为单列,可以提供 direction
参数为 Axis.vertical
。例如:
ToolBar.scroll(
toolBarColor: _toolbarColor,
controller: controller,
direction: Axis.vertical,
),
在这个例子中,ToolBar.scroll
小部件用于垂直排列工具栏按钮。
自定义工具栏按钮
ToolBar
小部件允许你自定义工具栏中显示的按钮。如果你不提供 toolBarConfig
参数,所有工具栏按钮都会显示。
如果你只想显示特定的按钮,可以通过向 toolBarConfig
参数传递一个 ToolBarStyle
类型的列表来实现。例如:
final customToolBarList = [
ToolBarStyle.bold,
ToolBarStyle.italic,
ToolBarStyle.align,
ToolBarStyle.color,
];
ToolBar(
controller: controller,
toolBarConfig: customToolBarList,
),
在这个例子中,只显示“加粗”、“斜体”、“对齐”和“颜色”按钮。
你还可以通过向 customButtons
参数提供一个包含自定义小部件的列表来添加自定义按钮。例如:
final customButtons = [
InkWell(onTap: () {}, child: const Icon(Icons.favorite)),
InkWell(onTap: () {}, child: const Icon(Icons.add_circle)),
];
ToolBar(
controller: controller,
customButtons: customButtons,
),
在这个例子中,添加了带有心形和圆形加号图标的心形和圆形加号按钮。
自定义字体
你可以通过以下步骤将自定义字体传递给文本样式:
在你的 Flutter 项目中定义自定义字体家族。你可以使用 Google Fonts。假设你想使用 ‘Roboto’ 字体家族。
final _editorTextStyle = const TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.normal,
fontFamily: 'Roboto',
);
通过这些步骤,你可以将自定义字体样式传递给 QuillHtmlEditor 小部件中的文本。fontFamily
属性允许你指定所需的字体家族,如本例中的 ‘Roboto’。
获取和设置 HTML 字符串
获取编辑器中的 HTML 字符串:
String? htmlText = await controller.getText();
设置编辑器中的 HTML 字符串:
await controller.setText(text);
获取 Delta 格式的文本:
await controller.getDelta();
设置 Delta 格式的文本:
controller.setDelta(deltaMap);
将 HTML 字符串插入到编辑器中:
await controller.insertText(text, index: 10);
清除编辑器:
controller.clear();
启用编辑器:
controller.enableEditor(true);
禁用编辑器:
controller.enableEditor(false);
示例代码
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:custom_quill_html_editor/custom_quill_html_editor.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late QuillEditorController controller;
final customToolBarList = [
ToolBarStyle.bold,
ToolBarStyle.italic,
ToolBarStyle.align,
ToolBarStyle.color,
ToolBarStyle.background,
ToolBarStyle.listBullet,
ToolBarStyle.listOrdered,
ToolBarStyle.clean,
ToolBarStyle.addTable,
ToolBarStyle.editTable,
];
final _toolbarColor = Colors.grey.shade200;
final _backgroundColor = Colors.white70;
final _toolbarIconColor = Colors.black87;
final _editorTextStyle = const TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.normal,
fontFamily: 'Roboto');
final _hintTextStyle = const TextStyle(
fontSize: 18, color: Colors.black38, fontWeight: FontWeight.normal);
bool _hasFocus = false;
[@override](/user/override)
void initState() {
controller = QuillEditorController();
controller.onTextChanged((text) {
debugPrint('listening to $text');
});
controller.onEditorLoaded(() {
debugPrint('Editor Loaded :)');
});
super.initState();
}
[@override](/user/override)
void dispose() {
controller.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomInset: true,
body: Column(
children: [
ToolBar(
toolBarColor: _toolbarColor,
padding: const EdgeInsets.all(8),
iconSize: 25,
iconColor: _toolbarIconColor,
activeIconColor: Colors.greenAccent.shade400,
controller: controller,
crossAxisAlignment: WrapCrossAlignment.start,
direction: Axis.horizontal,
customButtons: [
Container(
width: 25,
height: 25,
decoration: BoxDecoration(
color: _hasFocus ? Colors.green : Colors.grey,
borderRadius: BorderRadius.circular(15)),
),
InkWell(
onTap: () => unFocusEditor(),
child: const Icon(
Icons.favorite,
color: Colors.black,
)),
InkWell(
onTap: () async {
var selectedText = await controller.getSelectedText();
debugPrint('selectedText $selectedText');
var selectedHtmlText =
await controller.getSelectedHtmlText();
debugPrint('selectedHtmlText $selectedHtmlText');
},
child: const Icon(
Icons.add_circle,
color: Colors.black,
)),
],
),
Expanded(
child: QuillHtmlEditor(
text: "<h1>Hello</h1>This is a quill html editor example 😊",
hintText: 'Hint text goes here',
controller: controller,
isEnabled: true,
ensureVisible: false,
minHeight: 500,
autoFocus: false,
textStyle: _editorTextStyle,
hintTextStyle: _hintTextStyle,
hintTextAlign: TextAlign.start,
padding: const EdgeInsets.only(left: 10, top: 10),
hintTextPadding: const EdgeInsets.only(left: 20),
backgroundColor: _backgroundColor,
inputAction: InputAction.newline,
onEditingComplete: (s) => debugPrint('Editing completed $s'),
loadingBuilder: (context) {
return const Center(
child: CircularProgressIndicator(
strokeWidth: 1,
color: Colors.red,
));
},
onFocusChanged: (focus) {
debugPrint('has focus $focus');
setState(() {
_hasFocus = focus;
});
},
onTextChanged: (text) => debugPrint('widget text change $text'),
onEditorCreated: () {
debugPrint('Editor has been loaded');
setHtmlText('Testing text on load');
},
onEditorResized: (height) =>
debugPrint('Editor resized $height'),
onSelectionChanged: (sel) =>
debugPrint('index ${sel.index}, range ${sel.length}'),
),
),
],
),
bottomNavigationBar: Container(
width: double.maxFinite,
color: _toolbarColor,
padding: const EdgeInsets.all(8),
child: Wrap(
children: [
textButton(
text: 'Set Text',
onPressed: () {
setHtmlText('This text is set by you 🫵');
}),
textButton(
text: 'Get Text',
onPressed: () {
getHtmlText();
}),
textButton(
text: 'Insert Video',
onPressed: () {
insertVideoURL(
'https://www.youtube.com/watch?v=4AoFA19gbLo');
insertVideoURL('https://vimeo.com/440421754');
insertVideoURL(
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4');
}),
textButton(
text: 'Insert Image',
onPressed: () {
insertNetworkImage('https://i.imgur.com/0DVAOec.gif');
}),
textButton(
text: 'Insert Index',
onPressed: () {
insertHtmlText("This text is set by the insertText method",
index: 10);
}),
textButton(
text: 'Undo',
onPressed: () {
controller.undo();
}),
textButton(
text: 'Redo',
onPressed: () {
controller.redo();
}),
textButton(
text: 'Clear History',
onPressed: () async {
controller.clearHistory();
}),
textButton(
text: 'Clear Editor',
onPressed: () {
controller.clear();
}),
textButton(
text: 'Get Delta',
onPressed: () async {
var delta = await controller.getDelta();
debugPrint('delta');
debugPrint(jsonEncode(delta));
}),
textButton(
text: 'Set Delta',
onPressed: () {
final Map<dynamic, dynamic> deltaMap = {
"ops": [
{
"insert": {
"video":
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
}
},
{
"insert": {
"video": "https://www.youtube.com/embed/4AoFA19gbLo"
}
},
{"insert": "Hello"},
{
"attributes": {"header": 1},
"insert": "\n"
},
{"insert": "You just set the Delta text 😊\n"}
]
};
controller.setDelta(deltaMap);
}),
],
),
),
),
);
}
Widget textButton({required String text, required VoidCallback onPressed}) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: MaterialButton(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
color: _toolbarIconColor,
onPressed: onPressed,
child: Text(
text,
style: TextStyle(color: _toolbarColor),
)),
);
}
void getHtmlText() async {
String? htmlText = await controller.getText();
debugPrint(htmlText);
}
void setHtmlText(String text) async {
await controller.setText(text);
}
void insertNetworkImage(String url) async {
await controller.embedImage(url);
}
void insertVideoURL(String url) async {
await controller.embedVideo(url);
}
void insertHtmlText(String text, {int? index}) async {
await controller.insertText(text, index: index);
}
void clearEditor() => controller.clear();
void enableEditor(bool enable) => controller.enableEditor(enable);
void unFocusEditor() => controller.unFocus();
}
更多关于Flutter自定义HTML编辑器插件custom_quill_html_editor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter自定义HTML编辑器插件custom_quill_html_editor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用custom_quill_html_editor
插件的示例代码。这个插件允许你创建一个自定义的HTML编辑器,用户可以在其中输入和编辑富文本内容,然后将其转换为HTML格式。
首先,你需要在你的pubspec.yaml
文件中添加custom_quill_html_editor
依赖:
dependencies:
flutter:
sdk: flutter
custom_quill_html_editor: ^最新版本号 # 替换为实际的最新版本号
然后运行flutter pub get
来获取依赖。
接下来,你可以在你的Flutter项目中使用CustomQuillHtmlEditor
组件。以下是一个简单的示例,展示了如何集成和使用这个插件:
import 'package:flutter/material.dart';
import 'package:custom_quill_html_editor/custom_quill_html_editor.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill;
import 'package:flutter_quill/models/documents/document.dart' as quill;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Custom HTML Editor Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
quill.Document? _controllerDocument;
String _htmlContent = '';
@override
void initState() {
super.initState();
_controllerDocument = quill.Document();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Custom HTML Editor Demo'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: CustomQuillHtmlEditor(
controller: _CustomQuillController(
document: _controllerDocument!,
onChanged: (quill.Document doc) {
setState(() {
_controllerDocument = doc;
_htmlContent = doc.toDelta().map((e) => e.toHtml()).join();
});
},
),
),
),
SizedBox(height: 16),
Text(
'HTML Content:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Expanded(
child: SelectableText(
_htmlContent,
style: TextStyle(fontSize: 16),
maxLines: null,
),
),
],
),
),
);
}
}
class _CustomQuillController extends quill.QuillController {
_CustomQuillController({
required quill.Document document,
required VoidCallback Function(quill.Document doc) onChanged,
}) : super(
document: document,
selection: quill.TextSelection.collapsed(offset: 0),
onChanged: (quill.Delta delta, quill.ChangeSource source) {
if (source != quill.ChangeSource.silent) {
onChanged(document);
}
},
);
}
在这个示例中:
- 我们定义了一个
_CustomQuillController
类,它扩展了quill.QuillController
,并添加了一个自定义的onChanged
回调,用于在文档内容更改时更新HTML内容。 - 在
MyHomePage
中,我们使用CustomQuillHtmlEditor
组件来显示编辑器,并绑定到_CustomQuillController
。 - 当用户编辑内容时,
_CustomQuillController
的onChanged
回调会被触发,我们更新_htmlContent
变量,该变量保存了当前的HTML内容。 - 我们还使用了一个
SelectableText
组件来显示生成的HTML内容,以便用户可以看到他们的编辑结果。
请确保你遵循了custom_quill_html_editor
插件的文档和更新日志,因为插件的API可能会随着版本更新而变化。如果你遇到任何问题,请查阅最新的官方文档或提交issue到插件的GitHub仓库。