Flutter富文本编辑器插件quill_html_editor_v2的使用
Flutter富文本编辑器插件quill_html_editor_v2的使用
简介
quill_html_editor_v2
是一个功能强大的HTML富文本编辑器,适用于Android、iOS和Web平台。它基于QuillJs库,提供了丰富的编辑体验。该插件包括了许多更新和改进,以增强功能和性能。
功能特性
- 高度可定制的编辑器和工具栏:您可以根据需要自定义编辑器和工具栏的外观和行为。
- 支持Delta格式:您可以使用
setDelta
和getDelta
方法设置和获取内容。 - 无缝复制粘贴:支持从其他文件或网页中复制粘贴富文本。
- 可移动的工具栏:工具栏可以放置在页面的任何位置,以满足您的需求。
- 自定义按钮:您可以为工具栏添加自定义按钮。
- 嵌入图片、视频和插入表格:支持多媒体内容的嵌入。
- HTML和Delta格式的文本设置与获取:您可以设置和获取HTML和Delta格式的文本。
- 集成Google Fonts:提供多种字体选项。
示例图片
使用示例
以下是一个完整的示例代码,展示了如何使用quill_html_editor_v2
插件创建一个富文本编辑器。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:quill_html_editor_v2/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
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
/// 创建一个 QuillEditorController 以访问编辑器方法
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
void initState() {
controller = QuillEditorController();
controller.onTextChanged((text) {
debugPrint('listening to $text');
});
controller.onEditorLoaded(() {
debugPrint('Editor Loaded :)');
});
super.initState();
}
@override
void dispose() {
/// 请不要忘记释放控制器
controller.dispose();
super.dispose();
}
@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),
)),
);
}
/// 获取编辑器中的HTML文本
void getHtmlText() async {
String? htmlText = await controller.getText();
debugPrint(htmlText);
}
/// 设置编辑器中的HTML文本
void setHtmlText(String text) async {
await controller.setText(text);
}
/// 插入网络图片
void insertNetworkImage(String url) async {
await controller.embedImage(url);
}
/// 插入视频URL
/// 该方法会识别插入的URL并将其转换为可嵌入的URL
/// 例如:将YouTube视频转换为嵌入视频,Vimeo也是如此
void insertVideoURL(String url) async {
await controller.embedVideo(url);
}
/// 在指定索引处插入HTML文本
/// 如果未设置索引,则会在光标位置插入
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();
}
工具栏滚动配置
ToolBar.scroll
widget允许您根据指定的direction
参数将工具栏按钮显示为单行或单列。默认情况下,direction
设置为Axis.horizontal
,即按钮排列为单行。要将按钮显示为单列,可以将direction
设置为Axis.vertical
。例如:
ToolBar.scroll(
toolBarColor: _toolbarColor,
controller: controller,
direction: Axis.vertical,
),
自定义工具栏按钮
您可以自定义工具栏中显示的按钮。通过传递toolBarConfig
参数,您可以选择显示特定的按钮。例如:
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,
),
自定义字体
您可以通过定义自定义字体族来设置编辑器中的文本样式。例如,使用Google Fonts中的’Roboto’字体:
final _editorTextStyle = const TextStyle(
fontSize: 18,
color: Colors.black,
fontWeight: FontWeight.normal,
fontFamily: 'Roboto',
);
获取和设置文本
-
获取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);
更多关于Flutter富文本编辑器插件quill_html_editor_v2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter富文本编辑器插件quill_html_editor_v2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用quill_html_editor_v2
插件的示例代码。这个插件允许你实现一个功能丰富的富文本编辑器,并且能够将编辑内容转换为HTML格式。
首先,确保你的Flutter项目已经设置好,并且在pubspec.yaml
文件中添加了quill_html_editor_v2
依赖:
dependencies:
flutter:
sdk: flutter
quill_html_editor_v2: ^最新版本号 # 请替换为实际的最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,我们创建一个包含QuillHtmlEditor
的Flutter页面。以下是一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:quill_html_editor_v2/quill_html_editor_v2.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Quill Html Editor Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: QuillHtmlEditorDemo(),
);
}
}
class QuillHtmlEditorDemo extends StatefulWidget {
@override
_QuillHtmlEditorDemoState createState() => _QuillHtmlEditorDemoState();
}
class _QuillHtmlEditorDemoState extends State<QuillHtmlEditorDemo> {
final _controller = QuillController(
document: Document(),
)..addListener(() {
// 这里可以监听文档变化,比如保存内容到本地或进行其他处理
print('Document changed');
});
String? _htmlContent;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Quill Html Editor Demo'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: QuillHtmlEditor(
controller: _controller,
focusNode: FocusNode(),
padding: EdgeInsets.zero,
placeholder: 'Start typing...',
readOnly: false,
toolbarOptions: QuillToolbarOptions(
// 配置工具栏选项,可以根据需要添加或移除工具
theme: QuillToolbarTheme.light,
showIcons: true,
items: [
['bold', 'italic', 'underline', 'strike'],
['code-block'],
[{'header': 1}, {'header': 2}],
[{'indent': '-1'}, {'indent': '+1'}],
[{'list': 'ordered'}, {'list': 'bullet'}],
[{'script': 'sub'}, {'script': 'super'}],
[{'align': []}, {'align': ['left']}, {'align': ['right']}, {'align': ['center']}, {'align': ['justify']}],
[{'color': []}, {'background': []}],
[{'size': ['small'], 'header': 3}],
[{'font': []}, {'background': []}],
['clean'],
['link', 'image', 'video'],
],
),
),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
// 获取HTML内容
setState(() {
_htmlContent = _controller.documentToHtml();
});
// 打印或处理HTML内容
print(_htmlContent!);
},
child: Text('Get HTML Content'),
),
if (_htmlContent != null)
Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Text(
'HTML Content:\n$_htmlContent',
style: TextStyle(fontSize: 14),
),
),
],
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
这个示例代码展示了如何使用quill_html_editor_v2
插件来创建一个基本的富文本编辑器。主要步骤包括:
- 在
pubspec.yaml
中添加依赖。 - 创建一个
QuillController
实例来管理编辑器的状态。 - 使用
QuillHtmlEditor
组件来渲染编辑器界面。 - 配置工具栏选项以满足需求。
- 通过控制器获取编辑器内容并转换为HTML格式。
希望这个示例能帮助你更好地理解和使用quill_html_editor_v2
插件。如果有更多问题,欢迎继续提问!