Flutter富文本编辑器插件html_editor_enhanced_android_fix的使用

Flutter富文本编辑器插件html_editor_enhanced_android_fix的使用

html_editor_enhanced_android_fix 是一个用于在 Flutter 应用中实现富文本编辑功能的插件。它支持 Android、iOS 和 Web 平台,并提供了丰富的自定义选项来满足不同需求。

安装插件

首先,在 pubspec.yaml 文件中添加 html_editor_enhanced_android_fix 插件依赖:

dependencies:
  html_editor_enhanced_android_fix: ^2.5.0

然后运行 flutter pub get 来安装依赖。

Android 配置

确保在 AndroidManifest.xml 中声明互联网权限:

<uses-permission android:name="android.permission.INTERNET"/>

基本使用

以下是一个基本的使用示例:

import 'package:flutter/material.dart';
import 'package:html_editor_enhanced_android_fix/html_editor.dart';

void main() => runApp(HtmlEditorExampleApp());

class HtmlEditorExampleApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(),
      darkTheme: ThemeData.dark(),
      home: HtmlEditorExample(title: 'Flutter HTML Editor Example'),
    );
  }
}

class HtmlEditorExample extends StatefulWidget {
  HtmlEditorExample({Key? key, required this.title}) : super(key: key);

  final String title;

  [@override](/user/override)
  _HtmlEditorExampleState createState() => _HtmlEditorExampleState();
}

class _HtmlEditorExampleState extends State<HtmlEditorExample> {
  final HtmlEditorController controller = HtmlEditorController();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        if (!kIsWeb) {
          controller.clearFocus();
        }
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
          elevation: 0,
          actions: [
            IconButton(
                icon: Icon(Icons.refresh),
                onPressed: () {
                  if (kIsWeb) {
                    controller.reloadWeb();
                  } else {
                    controller.editorController!.reload();
                  }
                })
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            controller.toggleCodeView();
          },
          child: Text(r'<\>', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
        ),
        body: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              HtmlEditor(
                controller: controller,
                htmlEditorOptions: HtmlEditorOptions(
                  hint: 'Your text here...',
                  shouldEnsureVisible: true,
                ),
                htmlToolbarOptions: HtmlToolbarOptions(
                  toolbarPosition: ToolbarPosition.aboveEditor,
                  toolbarType: ToolbarType.nativeScrollable,
                  onButtonPressed: (ButtonType type, bool? status, Function? updateStatus) {
                    print("button '${describeEnum(type)}' pressed, the current selected status is $status");
                    return true;
                  },
                  onDropdownChanged: (DropdownType type, dynamic changed, Function(dynamic)? updateSelectedItem) {
                    print("dropdown '${describeEnum(type)}' changed to $changed");
                    return true;
                  },
                  mediaLinkInsertInterceptor: (String url, InsertFileType type) {
                    print(url);
                    return true;
                  },
                  mediaUploadInterceptor: (PlatformFile file, InsertFileType type) async {
                    print(file.name); //filename
                    print(file.size); //size in bytes
                    print(file.extension); //file extension (eg jpeg or mp4)
                    return true;
                  },
                ),
                otherOptions: OtherOptions(height: 550),
                callbacks: Callbacks(
                  onBeforeCommand: (String? currentHtml) {
                    print('html before change is $currentHtml');
                  },
                  onChangeContent: (String? changed) {
                    print('content changed to $changed');
                  },
                  onChangeCodeview: (String? changed) {
                    print('code changed to $changed');
                  },
                  onChangeSelection: (EditorSettings settings) {
                    print('parent element is ${settings.parentElement}');
                    print('font name is ${settings.fontName}');
                  },
                  onDialogShown: () {
                    print('dialog shown');
                  },
                  onEnter: () {
                    print('enter/return pressed');
                  },
                  onFocus: () {
                    print('editor focused');
                  },
                  onBlur: () {
                    print('editor unfocused');
                  },
                  onBlurCodeview: () {
                    print('codeview either focused or unfocused');
                  },
                  onInit: () {
                    print('init');
                  },
                  onImageUploadError: (FileUpload? file, String? base64Str, UploadError error) {
                    print(describeEnum(error));
                    print(base64Str ?? '');
                    if (file != null) {
                      print(file.name);
                      print(file.size);
                      print(file.type);
                    }
                  },
                  onKeyDown: (int? keyCode) {
                    print('$keyCode key downed');
                    print('current character count: ${controller.characterCount}');
                  },
                  onKeyUp: (int? keyCode) {
                    print('$keyCode key released');
                  },
                  onMouseDown: () {
                    print('mouse downed');
                  },
                  onMouseUp: () {
                    print('mouse released');
                  },
                  onNavigationRequestMobile: (String url) {
                    print(url);
                    return NavigationActionPolicy.ALLOW;
                  },
                  onPaste: () {
                    print('pasted into editor');
                  },
                  onScroll: () {
                    print('editor scrolled');
                  },
                ),
                plugins: [
                  SummernoteAtMention(
                    getSuggestionsMobile: (String value) {
                      var mentions = ['test1', 'test2', 'test3'];
                      return mentions
                          .where((element) => element.contains(value))
                          .toList();
                    },
                    mentionsWeb: ['test1', 'test2', 'test3'],
                    onSelect: (String value) {
                      print(value);
                    },
                  ),
                ],
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.undo();
                      },
                      child: Text('Undo', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.clear();
                      },
                      child: Text('Reset', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        var txt = await controller.getText();
                        if (txt.contains('src=\"data:')) {
                          txt = '<text removed due to base-64 data, displaying the text could cause the app to crash>';
                        }
                        setState(() {
                          result = txt;
                        });
                      },
                      child: Text(
                        'Submit',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller.redo();
                      },
                      child: Text(
                        'Redo',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text(result),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.disable();
                      },
                      child: Text('Disable', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        controller.enable();
                      },
                      child: Text(
                        'Enable',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
              SizedBox(height: 16),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller.insertText('Google');
                      },
                      child: Text('Insert Text', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller
                            .insertHtml('<p style="color: blue">Google in blue</p>');
                      },
                      child: Text('Insert HTML', style: TextStyle(color: Colors.white)),
                    ),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        controller.insertLink(
                            'Google linked', 'https://google.com', true);
                      },
                      child: Text(
                        'Insert Link',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller.insertNetworkImage(
                            'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png',
                            filename: 'Google network image');
                      },
                      child: Text(
                        'Insert network image',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
              SizedBox(height: 16),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.addNotification(
                            'Info notification', NotificationType.info);
                      },
                      child: Text('Info', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.addNotification(
                            'Warning notification', NotificationType.warning);
                      },
                      child: Text('Warning', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        controller.addNotification(
                            'Success notification', NotificationType.success);
                      },
                      child: Text(
                        'Success',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller.addNotification(
                            'Danger notification', NotificationType.danger);
                      },
                      child: Text(
                        'Danger',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
              SizedBox(height: 16),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.addNotification(
                            'Plaintext notification', NotificationType.plaintext);
                      },
                      child: Text('Plaintext', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        controller.removeNotification();
                      },
                      child: Text(
                        'Remove',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

API 参考

参数 - HtmlEditor

参数 类型 默认值 描述
controller HtmlEditorController 必需参数。创建一个控制器实例并传递给小部件。这确保任何方法仅在其HtmlEditor实例上工作,允许在一个页面上使用多个HTML小部件。
callbacks Callbacks 自定义各种事件的回调。
options HtmlEditorOptions HtmlEditorOptions() 设置各种选项的类。更多详情见下文。
plugins List<Plugins> 自定义激活哪些插件。更多详情见下文。
toolbar List<Toolbar> 见小部件的构造函数 自定义工具栏上显示的按钮及其顺序。更多详情见下文。

参数 - HtmlEditorController

参数 类型 默认值 描述
processInputHtml bool true 确定是否对任何输入HTML进行处理(例如转义引号、撇号并移除\ns)。
processNewLineAsBr bool false 确定任何输入HTML中的新行(\n)是否变为<br/>
processOutputHtml bool true 确定是否对任何输出HTML进行处理(例如<p><br/></p>变为"")。

参数 - HtmlEditorOptions

参数 类型 默认值 描述
autoAdjustHeight bool true 自动调整文本编辑器的高度。建议值为true。 更多详情见下文。
adjustHeightForKeyboard bool true 如果键盘处于活动状态且重叠了编辑器,则调整编辑器高度以防止重叠。建议值为true,仅在移动设备上有效。 更多详情见下文。
filePath String 允许指定要加载到webview中的自定义HTML。您可以创建一个带有Summernote的自定义页面,或理论上加载任何其他编辑器/HTML。
shouldEnsureVisible bool false 当webview聚焦时,将父Scrollable滚动到编辑器小部件的顶部。 不要在HtmlEditor不在Scrollable内时使用此参数。 更多详情见下文。
webInitialScripts UnmodifiableListView<WebScript> 轻松注入脚本来执行操作,如更改编辑器的背景颜色。 更多详情见下文。

参数 - HtmlToolbarOptions

参数 类型 默认值 描述
customToolbarButtons List<Widget> 向工具栏添加自定义按钮。
customToolbarInsertionIndices List<int> 允许设置每个自定义工具栏按钮应插入到工具栏小部件列表的位置。
onButtonPressed FutureOr<bool> Function(ButtonType, bool?, void Function()?) 截获任何按钮按下事件。该函数传递按下的按钮枚举、当前选择状态(如果适用)以及更新状态的函数(如果适用)。
onDropdownChanged FutureOr<bool> Function(DropdownType, dynamic, void Function(dynamic)?) 截获任何下拉框更改事件。该函数传递更改的下拉框枚举、更改的值以及更新更改值的函数(如果适用)。

示例

示例代码

以下是一个完整的示例代码,展示了如何使用 html_editor_enhanced_android_fix 插件创建一个富文本编辑器:

import 'package:flutter/material.dart';
import 'package:html_editor_enhanced_android_fix/html_editor.dart';

void main() => runApp(HtmlEditorExampleApp());

class HtmlEditorExampleApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(),
      darkTheme: ThemeData.dark(),
      home: HtmlEditorExample(title: 'Flutter HTML Editor Example'),
    );
  }
}

class HtmlEditorExample extends StatefulWidget {
  HtmlEditorExample({Key? key, required this.title}) : super(key: key);

  final String title;

  [@override](/user/override)
  _HtmlEditorExampleState createState() => _HtmlEditorExampleState();
}

class _HtmlEditorExampleState extends State<HtmlEditorExample> {
  final HtmlEditorController controller = HtmlEditorController();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        if (!kIsWeb) {
          controller.clearFocus();
        }
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
          elevation: 0,
          actions: [
            IconButton(
                icon: Icon(Icons.refresh),
                onPressed: () {
                  if (kIsWeb) {
                    controller.reloadWeb();
                  } else {
                    controller.editorController!.reload();
                  }
                })
          ],
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            controller.toggleCodeView();
          },
          child: Text(r'<\>', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
        ),
        body: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              HtmlEditor(
                controller: controller,
                htmlEditorOptions: HtmlEditorOptions(
                  hint: 'Your text here...',
                  shouldEnsureVisible: true,
                ),
                htmlToolbarOptions: HtmlToolbarOptions(
                  toolbarPosition: ToolbarPosition.aboveEditor,
                  toolbarType: ToolbarType.nativeScrollable,
                  onButtonPressed: (ButtonType type, bool? status, Function? updateStatus) {
                    print("button '${describeEnum(type)}' pressed, the current selected status is $status");
                    return true;
                  },
                  onDropdownChanged: (DropdownType type, dynamic changed, Function(dynamic)? updateSelectedItem) {
                    print("dropdown '${describeEnum(type)}' changed to $changed");
                    return true;
                  },
                  mediaLinkInsertInterceptor: (String url, InsertFileType type) {
                    print(url);
                    return true;
                  },
                  mediaUploadInterceptor: (PlatformFile file, InsertFileType type) async {
                    print(file.name); //filename
                    print(file.size); //size in bytes
                    print(file.extension); //file extension (eg jpeg or mp4)
                    return true;
                  },
                ),
                otherOptions: OtherOptions(height: 550),
                callbacks: Callbacks(
                  onBeforeCommand: (String? currentHtml) {
                    print('html before change is $currentHtml');
                  },
                  onChangeContent: (String? changed) {
                    print('content changed to $changed');
                  },
                  onChangeCodeview: (String? changed) {
                    print('code changed to $changed');
                  },
                  onChangeSelection: (EditorSettings settings) {
                    print('parent element is ${settings.parentElement}');
                    print('font name is ${settings.fontName}');
                  },
                  onDialogShown: () {
                    print('dialog shown');
                  },
                  onEnter: () {
                    print('enter/return pressed');
                  },
                  onFocus: () {
                    print('editor focused');
                  },
                  onBlur: () {
                    print('editor unfocused');
                  },
                  onBlurCodeview: () {
                    print('codeview either focused or unfocused');
                  },
                  onInit: () {
                    print('init');
                  },
                  onImageUploadError: (FileUpload? file, String? base64Str, UploadError error) {
                    print(describeEnum(error));
                    print(base64Str ?? '');
                    if (file != null) {
                      print(file.name);
                      print(file.size);
                      print(file.type);
                    }
                  },
                  onKeyDown: (int? keyCode) {
                    print('$keyCode key downed');
                    print('current character count: ${controller.characterCount}');
                  },
                  onKeyUp: (int? keyCode) {
                    print('$keyCode key released');
                  },
                  onMouseDown: () {
                    print('mouse downed');
                  },
                  onMouseUp: () {
                    print('mouse released');
                  },
                  onNavigationRequestMobile: (String url) {
                    print(url);
                    return NavigationActionPolicy.ALLOW;
                  },
                  onPaste: () {
                    print('pasted into editor');
                  },
                  onScroll: () {
                    print('editor scrolled');
                  },
                ),
                plugins: [
                  SummernoteAtMention(
                    getSuggestionsMobile: (String value) {
                      var mentions = ['test1', 'test2', 'test3'];
                      return mentions
                          .where((element) => element.contains(value))
                          .toList();
                    },
                    mentionsWeb: ['test1', 'test2', 'test3'],
                    onSelect: (String value) {
                      print(value);
                    },
                  ),
                ],
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.undo();
                      },
                      child: Text('Undo', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.clear();
                      },
                      child: Text('Reset', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        var txt = await controller.getText();
                        if (txt.contains('src=\"data:')) {
                          txt = '<text removed due to base-64 data, displaying the text could cause the app to crash>';
                        }
                        setState(() {
                          result = txt;
                        });
                      },
                      child: Text(
                        'Submit',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller.redo();
                      },
                      child: Text(
                        'Redo',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text(result),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.disable();
                      },
                      child: Text('Disable', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        controller.enable();
                      },
                      child: Text(
                        'Enable',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
              SizedBox(height: 16),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller.insertText('Google');
                      },
                      child: Text('Insert Text', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller
                            .insertHtml('<p style="color: blue">Google in blue</p>');
                      },
                      child: Text('Insert HTML', style: TextStyle(color: Colors.white)),
                    ),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        controller.insertLink(
                            'Google linked', 'https://google.com', true);
                      },
                      child: Text(
                        'Insert Link',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller.insertNetworkImage(
                            'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png',
                            filename: 'Google network image');
                      },
                      child: Text(
                        'Insert network image',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
              SizedBox(height: 16),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.addNotification(
                            'Info notification', NotificationType.info);
                      },
                      child: Text('Info', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.addNotification(
                            'Warning notification', NotificationType.warning);
                      },
                      child: Text('Warning', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        controller.addNotification(
                            'Success notification', NotificationType.success);
                      },
                      child: Text(
                        'Success',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () {
                        controller.addNotification(
                            'Danger notification', NotificationType.danger);
                      },
                      child: Text(
                        'Danger',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
              SizedBox(height: 16),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    TextButton(
                      style: TextButton.styleFrom(backgroundColor: Colors.blueGrey),
                      onPressed: () {
                        controller.addNotification(
                            'Plaintext notification', NotificationType.plaintext);
                      },
                      child: Text('Plaintext', style: TextStyle(color: Colors.white)),
                    ),
                    SizedBox(width: 16),
                    TextButton(
                      style: TextButton.styleFrom(
                          backgroundColor: Theme.of(context).colorScheme.secondary),
                      onPressed: () async {
                        controller.removeNotification();
                      },
                      child: Text(
                        'Remove',
                        style: TextStyle(color: Colors.white),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter富文本编辑器插件html_editor_enhanced_android_fix的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter富文本编辑器插件html_editor_enhanced_android_fix的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


html_editor_enhanced_android_fix 是一个用于 Flutter 的富文本编辑器插件,它基于 html_editor_enhanced,并修复了一些在 Android 平台上的问题。这个插件允许你在 Flutter 应用中嵌入一个功能丰富的 HTML 编辑器,支持文本格式化、插入图片、链接等功能。

安装

首先,你需要在 pubspec.yaml 文件中添加 html_editor_enhanced_android_fix 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  html_editor_enhanced_android_fix: ^1.0.0

然后运行 flutter pub get 来安装依赖。

基本用法

以下是一个简单的示例,展示了如何在 Flutter 应用中使用 html_editor_enhanced_android_fix 插件:

import 'package:flutter/material.dart';
import 'package:html_editor_enhanced_android_fix/html_editor.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter HTML Editor',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HtmlEditorExample(),
    );
  }
}

class HtmlEditorExample extends StatefulWidget {
  [@override](/user/override)
  _HtmlEditorExampleState createState() => _HtmlEditorExampleState();
}

class _HtmlEditorExampleState extends State<HtmlEditorExample> {
  final HtmlEditorController controller = HtmlEditorController();

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('HTML Editor Enhanced Android Fix'),
        actions: [
          IconButton(
            icon: Icon(Icons.save),
            onPressed: () async {
              final String? html = await controller.getText();
              print(html);
            },
          ),
        ],
      ),
      body: SingleChildScrollView(
        child: Column(
          children: [
            HtmlEditor(
              controller: controller,
              htmlEditorOptions: HtmlEditorOptions(
                hint: "Your text here...",
                shouldEnsureVisible: true,
              ),
              htmlToolbarOptions: HtmlToolbarOptions(
                defaultToolbarButtons: [
                  StyleButtons(),
                  FontSettingButtons(),
                  ListButtons(),
                  ParagraphButtons(),
                  InsertButtons(),
                ],
              ),
              otherOptions: OtherOptions(
                height: 300,
              ),
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部