Flutter富文本编辑器插件remodl_rte的使用
Flutter富文本编辑器插件remodl_rte的使用
Remodl.ai富文本编辑器
这是一个适用于Flutter的所见即所得(WYSIWYG)HTML编辑器,并内置了语音转文字功能。
背后原理
该插件基于html_editor_enhanced进行了重新开发,主要区别包括:
-
改进了小部件的高度约束:
- 自动适应内容高度,
- 扩展到全高,
- 显式指定。
-
使用了Squire代替了Summernote和jQuery,这是一款非常流行且维护良好的HTML5富文本编辑库,提供了对生成HTML的强大灵活性。
-
通过DOMPurify进行XSS防护,这是一款超快且容错性极高的HTML、MathML和SVG XSS清理工具。
-
使用Flutter自己的webview_flutter代替了in_app_webview。
-
内置的语音转文字功能由speech_to_text包提供支持(主要针对Web平台)。
基本实现
基本实现无需控制器。为了简化和易于使用,[HtmlEditor]提供了以下顶级属性:
字段 | 类型 | 描述 |
---|---|---|
height |
double | 设置显式高度 |
minHeight |
double | 设置最小高度 |
expandFullHeight |
bool | 使小部件占用所有可用高度 |
hint |
String | 编辑器为空时显示提示文本 |
initialValue |
String | 初始HTML或文本 |
onChanged |
String | 控制器onChanged 回调的快捷方式 |
isReadOnly |
bool | 锁定编辑器并移除工具栏 |
enableDictation |
bool | 启用或禁用语音转文字功能 |
import 'package:remodl_rte/remodl_rte.dart';
// ...
// 1. 定义一个变量来存储父类或其他地方的变化结果
String result = 'Hello world!';
// ...
// 2. 在构建方法中添加HtmlEditor
@override
Widget build(BuildContext context) =>
HtmlEditor(initialValue: result, onChanged: (s) => result = s ?? '');
高级实现
要充分利用整个API,你需要创建并配置一个[HtmlEditorController]实例。该实例提供了以下选项组的访问权限:
- 样式选项组(所有CSS、HTML和清理)
- 工具栏选项组(所有工具栏)
- 编辑器选项组(所有编辑器)
使用控制器时,可以通过controller.setText()
方法设置HtmlEditor的文本。这可以在控制器附加到HtmlEditor之前或之后完成。这对于MVVM/MVC情况很有用,在这些情况下,逻辑在UI构建之前被初始化。
可以通过getter同步访问编辑器的内容:
if (controller.contentIsNotEmpty) {
Navigator.of(context).pop(controller.content);
}
HTML样式选项
[HtmlEditorController]类的stylingOptions
参数定义了生成HTML的外观。你可以选择用于段落的标签以及如何设置标签的样式。
var stylingOptions = HtmlStylingOptions(
// 可选地添加全局样式,可以通过两种方式设置:
// 1. 提供CSS字符串给`globalStyleSheet`参数:
globalStyleSheet: '/* Your CSS string contents of style.css file */',
// 这里定义用于段落的标签。默认值为`p`,但`div`也是可以接受的。
blockTag: 'p',
// 定义块标签的`style`和`class`属性
blockTagAttributes: HtmlTagAttributes(
// 这将作为每个标签的内联CSS添加
inlineStyle: 'text-indent:3.5em; text-align:justify;',
// 定义每个标签的`class`属性值
cssClass: 'my-custom-pgf'),
// 接下来我们可以定义其他标签(如li、ul、ol、a等)的属性:
li: HtmlTagAttributes(
inlineStyle: 'margin: .5em 1em .5em .5em',
cssClass: 'my-custom-li-class'),
// ... 其他HTML标签定义 ... //
code: HtmlTagAttributes(
inlineStyle: 'padding: .5em 1em;', cssClass: 'my-custom-code-class'),
// 当`sanitizeOnPaste`为`true`时,编辑器会清理所有传入的HTML。
// !!! 危险 !!! 如果将此标志设置为`false`,则会使您的应用程序容易受到XSS攻击。
sanitizeOnPaste: true,
);
// 2. 另一种添加全局CSS的方式是调用此异步方法:
await stylingOptions.importCssFromFile('path/to/style.css');
// ...
// 现在创建编辑器并传递样式选项
return HtmlEditor(
controller: HtmlEditorController(stylingOptions: stylingOptions),
onChanged: (p0) => (p0) {/* TODO */},
initialValue: '' /* TODO */,
);
上述代码应该会生成以下HTML:
<p style="text-indent:3.5em; text-align:justify;" class="my-custom-pgf"></p>
尺寸和约束
默认情况下,小部件占据所有可用宽度,并根据其内容的高度调整其高度,但不会小于[HtmlEditor]小部件的minHeight
属性值。
// 由于未提供显式高度,因此编辑器将根据内容大小调整高度,但不会小于250px
return HtmlEditor(
controller: controller,
// ...
minHeight: 250, // 应该不小于64px
// ...
);
// 这里可以监听编辑器高度的变化
ValueListenableBuilder<double>(
valueListenable: controller.totalHeight,
builder: (BuildContext context, double value, Widget? child) {
return Text('Height changed to $value\n'
'Toolbar height is ${controller.toolbarHeight}\n'
'Content height is ${controller.contentHeight}\n');
}
);
// 如果提供了显式`height`,则小部件将精确调整到`height`属性的值。在这种情况下,如果内容高度超过小部件高度,则内容将可滚动。
return HtmlEditor(
height: 250,
);
// 如果设置了`expandFullHeight`为`true`,则小部件将占用所有可用高度。
return HtmlEditor(
expandFullHeight: true,
);
工具栏位置
所有与工具栏相关的选项都包含在[HtmlEditorController]类的[ToolbarOptions]中。工具栏可以:
- 上方或下方编辑器容器,通过设置
toolbarPosition
属性; - 浮动,即脱离编辑器并位于[HtmlEditor]小部件外部。这种实现允许[ToolbarWidget]附加到多个HtmlEditors。有关这种类型的实现,请参阅包中的示例。
上方编辑器:
下方编辑器:
浮动工具栏:
工具栏类型也可以设置为滚动、网格或可扩展。
工具栏内容和自定义按钮组
可以通过[HtmlToolbarOptions]类的defaultToolbarButtons
属性启用/禁用工具栏按钮组。你可以通过覆盖此属性的默认值来自定义工具栏。
要向工具栏添加自己的按钮组,需要向customButtonGroups
属性提供一个[CustomButtonGroup]对象列表。每个按钮组由一组[CustomToolbarButton]对象组成,每个对象都有自己的图标、点击回调和isSelected
标志,以告知工具栏是否应突出显示该图标按钮。
HtmlEditor(
controller: HtmlEditorController()
..toolbarOptions.customButtonGroups = [
CustomButtonGroup(
index: 0, // 放在第一位
buttons: [
CustomToolbarButton(
icon: Icons.save_outlined,
action: () => /* TODO: 实现你的保存方法 */,
isSelected: false
)
]
)
],
),
自定义按钮:
语音转文字(Dictation)
语音转文字功能由speech_to_text包提供支持,并且默认情况下已启用。
要禁用语音转文字功能,只需将相应的顶级enableDictation
属性设置为false
。
覆盖controller.toolbarOptions.defaultToolbarButtons
值也会覆盖enableDictation
标志(显然),因此需要添加const VoiceToTextButtons()
以继续显示语音转文字按钮。
特殊注意事项和陷阱
-
由于一些框架问题,在Web平台上,此插件仅兼容Flutter 3.3及以上版本。如果你希望在较早版本的Flutter中使用此插件,请确保将项目中的
pointer_interceptor
依赖项降级为0.9.0+1
。 -
为使每种平台正常工作,需要执行以下操作:
Android
对于语音识别功能,请将以下内容放置到android > app > src > main > AndroidManifest.xml
文件中:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.example">
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<application
...
iOS
对于语音识别功能,请在Info.plist
文件中添加以下权限:
<key>NSSpeechRecognitionUsageDescription</key>
<string>recognize speech</string>
<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for uploading videos</string>
Web平台
要在Web上使工具栏水平滚动,需要覆盖默认的滚动行为:
- 在你的应用中添加以下类覆盖:
class MyCustomScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
- 在[MaterialApp]小部件中添加以下属性:
return MaterialApp(
// ...
scrollBehavior: MyCustomScrollBehavior(),
// ...
);
更多关于Flutter富文本编辑器插件remodl_rte的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter富文本编辑器插件remodl_rte的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用remodl_rte
富文本编辑器插件的一个基本示例。remodl_rte
是一个功能强大的Flutter插件,用于创建富文本编辑器。
首先,你需要在你的pubspec.yaml
文件中添加remodl_rte
依赖:
dependencies:
flutter:
sdk: flutter
remodl_rte: ^最新版本号 # 请替换为实际可用的最新版本号
然后运行flutter pub get
来获取依赖。
接下来,在你的Dart文件中(例如main.dart
),你可以这样使用remodl_rte
:
import 'package:flutter/material.dart';
import 'package:remodl_rte/remodl_rte.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Rich Text Editor Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late RTEditorController _controller;
@override
void initState() {
super.initState();
_controller = RTEditorController(
initialText: 'Hello, Rich Text Editor!',
initialTextAlignment: TextAlignment.left,
initialTextStyle: TextStyle(fontSize: 16, color: Colors.black),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Rich Text Editor Demo'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: RTEditor(
controller: _controller,
readOnly: false,
showPlaceholder: true,
placeholder: 'Enter your text here...',
toolbarOptions: [
RTEToolbarOption.bold,
RTEToolbarOption.italic,
RTEToolbarOption.underline,
RTEToolbarOption.heading1,
RTEToolbarOption.heading2,
RTEToolbarOption.paragraph,
RTEToolbarOption.quote,
RTEToolbarOption.bulletList,
RTEToolbarOption.numberedList,
RTEToolbarOption.link,
RTEToolbarOption.image,
// 添加其他你需要的工具栏选项
],
onTextChange: (text) {
print('Text changed: $text');
},
onImagePick: (File? image) async {
if (image != null) {
// 处理图片上传或显示逻辑
// 例如将图片转换为Base64字符串或直接显示
print('Image picked: ${image.path}');
}
},
onLinkInsert: (String? url) {
print('Link inserted: $url');
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 获取富文本内容
final htmlContent = _controller.getHtmlContent();
// 你可以在这里处理htmlContent,例如保存到服务器或显示在一个WebView中
print('HTML Content: $htmlContent');
},
tooltip: 'Get HTML',
child: Icon(Icons.copy),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
代码解释
- 添加依赖:在
pubspec.yaml
文件中添加remodl_rte
依赖。 - 创建Flutter应用:在
main.dart
中创建一个基本的Flutter应用。 - 初始化
RTEditorController
:在initState
方法中初始化RTEditorController
,设置初始文本和样式。 - 构建UI:使用
RTEditor
小部件来创建富文本编辑器,并配置工具栏选项。 - 处理文本和图片变化:使用
onTextChange
和onImagePick
回调来处理文本和图片的变化。 - 获取HTML内容:在FloatingActionButton的点击事件中获取编辑器生成的HTML内容。
注意事项
- 确保你使用的
remodl_rte
版本与Flutter SDK兼容。 - 根据实际需求调整工具栏选项和回调函数。
- 你可以扩展这个示例以处理更多复杂的情况,例如将富文本内容保存到服务器或显示在一个WebView中。
希望这个示例能帮助你快速上手remodl_rte
富文本编辑器插件!