{"id":13551237,"url":"https://github.com/fluttercandies/extended_text","last_synced_at":"2025-05-14T22:07:33.971Z","repository":{"id":38805777,"uuid":"175116987","full_name":"fluttercandies/extended_text","owner":"fluttercandies","description":"A powerful extended official text for Flutter, which supports Speical Text(Image,@somebody), Custom Background, Custom overFlow, Text Selection.","archived":false,"fork":false,"pushed_at":"2025-03-21T05:07:38.000Z","size":8734,"stargazers_count":689,"open_issues_count":10,"forks_count":137,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-13T21:33:55.432Z","etag":null,"topics":["flutter","inline-image","overflow-text","richtext","selection","toolbar"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluttercandies.png","metadata":{"files":{"readme":"README-ZH.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"custom":"http://zmtzawqlp.gitee.io/my_images/images/qrcode.png"}},"created_at":"2019-03-12T02:08:57.000Z","updated_at":"2025-04-04T04:07:22.000Z","dependencies_parsed_at":"2023-02-14T05:46:24.795Z","dependency_job_id":"5a41f94f-1754-40a5-b682-30320509bf6a","html_url":"https://github.com/fluttercandies/extended_text","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fextended_text","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fextended_text/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fextended_text/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluttercandies%2Fextended_text/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluttercandies","download_url":"https://codeload.github.com/fluttercandies/extended_text/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254235696,"owners_count":22036963,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flutter","inline-image","overflow-text","richtext","selection","toolbar"],"created_at":"2024-08-01T12:01:44.643Z","updated_at":"2025-05-14T22:07:28.958Z","avatar_url":"https://github.com/fluttercandies.png","language":"Dart","readme":"# extended_text\n\n[![pub package](https://img.shields.io/pub/v/extended_text.svg)](https://pub.dartlang.org/packages/extended_text) [![GitHub stars](https://img.shields.io/github/stars/fluttercandies/extended_text)](https://github.com/fluttercandies/extended_text/stargazers) [![GitHub forks](https://img.shields.io/github/forks/fluttercandies/extended_text)](https://github.com/fluttercandies/extended_text/network)  [![GitHub license](https://img.shields.io/github/license/fluttercandies/extended_text)](https://github.com/fluttercandies/extended_text/blob/master/LICENSE)  [![GitHub issues](https://img.shields.io/github/issues/fluttercandies/extended_text)](https://github.com/fluttercandies/extended_text/issues) \u003ca target=\"_blank\" href=\"https://jq.qq.com/?_wv=1027\u0026k=5bcc0gy\"\u003e\u003cimg border=\"0\" src=\"https://pub.idqqimg.com/wpa/images/group.png\" alt=\"flutter-candies\" title=\"flutter-candies\"\u003e\u003c/a\u003e\n\n文档语言: [English](README.md) | 中文简体\n\n官方Text扩展组件，支持特殊文本效果（比如图片，@人）,自定义背景，自定义文本溢出效果,文本选择以及自定义选择菜单和选择器\n\n[ExtendedText 在线 Demo](https://fluttercandies.github.io/extended_text/)\n\n- [Flutter RichText 支持图片显示和自定义图片效果](https://juejin.im/post/5c8be0d06fb9a049a42ff067)\n- [Flutter RichText 支持自定义文本溢出效果](https://juejin.im/post/5c8ca608f265da2dd6394001)\n- [Flutter RichText 支持自定义文字背景](https://juejin.im/post/5c8bf9516fb9a049c9669204)\n- [Flutter RichText 支持特殊文字效果](https://juejin.im/post/5c8bf4fce51d451066008fa2)\n- [Flutter RichText 支持文本选择](https://juejin.im/post/5cff71d46fb9a07ea6486a0e)\n- [Flutter Text: 扶我起来](https://juejin.cn/post/6955095562215489573)\n- [Flutter 我就要五彩斑斓渐进的黑](https://juejin.cn/post/7411799494415728674)\n\n\nExtendedText 是 Flutter 官方 Text 的三方扩展库，主要扩展功能如下:\n| 功能                       | ExtendedText                                                | Flutter 官方 Text                                                                                                           |\n| -------------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |\n| 支持自定义文本溢出效果     | 支持，可以自定义溢出的 Widget，并控制溢出位置（前、中、后） | 不支 持 ([26748](https://github.com/flutter/flutter/issues/26748),[45336](https://github.com/flutter/flutter/issues/45336)) |\n| 支持复制特殊文本的真实值   | 支持，可以复制出文本的真实值，而不仅是 WidgetSpan 的占位值  | 只能复制出 WidgetSpan 的占位值 (\\uFFFC)                                                                                     |\n| 根据文本格式快速构建富文本 | 支持，可以根据文本格式快速构建富文本                        | 不支持                                                                                                                      |\n\n\u003e 已支持 `HarmonyOS`. 请使用最新的带有 `ohos` 标志的版本. 你可以在 `Versions` 签查找.\n\n```yaml\ndependencies:\n  extended_text: 10.0.1-ohos //  3.7.12\n  extended_text: 13.0.2      //  3.22.0\n```\n\n## 目录\n \n- [extended\\_text](#extended_text)\n  - [目录](#目录)\n  - [特殊文本](#特殊文本)\n    - [创建特殊文本](#创建特殊文本)\n    - [特殊文本Builder](#特殊文本builder)\n  - [图片](#图片)\n    - [ImageSpan](#imagespan)\n  - [文本选择](#文本选择)\n    - [文本选择控制器](#文本选择控制器)\n  - [自定义背景](#自定义背景)\n  - [自定义文本溢出](#自定义文本溢出)\n  - [Join Zero-Width Space](#join-zero-width-space)\n  - [Gradient](#gradient)\n    - [GradientConfig](#gradientconfig)\n    - [IgnoreGradientSpan](#ignoregradientspan)\n  - [☕️Buy me a coffee](#️buy-me-a-coffee)\n\n\n## 特殊文本\n\n![](https://github.com/fluttercandies/Flutter_Candies/blob/master/gif/extended_text/special_text.jpg)\n\n\n### 创建特殊文本\n\nextended_text 帮助将字符串文本快速转换为特殊的TextSpan\n\n下面的例子告诉你怎么创建一个@xxx\n\n具体思路是对字符串进行进栈遍历，通过判断flag来判定是否是一个特殊字符。\n例子：@zmtzawqlp ，以@开头并且以空格结束，我们就认为它是一个@的特殊文本\n\n```dart\nclass AtText extends SpecialText {\n  AtText(TextStyle textStyle, SpecialTextGestureTapCallback onTap,\n      {this.showAtBackground = false, this.start})\n      : super(flag, ' ', textStyle, onTap: onTap);\n  static const String flag = '@';\n  final int start;\n\n  /// whether show background for @somebody\n  final bool showAtBackground;\n\n  @override\n  InlineSpan finishText() {\n    final TextStyle textStyle =\n        this.textStyle?.copyWith(color: Colors.blue, fontSize: 16.0);\n\n    final String atText = toString();\n\n    return showAtBackground\n        ? BackgroundTextSpan(\n            background: Paint()..color = Colors.blue.withOpacity(0.15),\n            text: atText,\n            actualText: atText,\n            start: start,\n\n            ///caret can move into special text\n            deleteAll: true,\n            style: textStyle,\n            recognizer: (TapGestureRecognizer()\n              ..onTap = () {\n                if (onTap != null) {\n                  onTap(atText);\n                }\n              }))\n        : SpecialTextSpan(\n            text: atText,\n            actualText: atText,\n            start: start,\n            style: textStyle,\n            recognizer: (TapGestureRecognizer()\n              ..onTap = () {\n                if (onTap != null) {\n                  onTap(atText);\n                }\n              }));\n  }\n}\n\n```\n\n### 特殊文本Builder\n\n创建属于你自己规则的Builder，上面说了你可以继承SpecialText来定义各种各样的特殊文本。\n- build 方法中，是通过具体思路是对字符串进行进栈遍历，通过判断flag来判定是否是一个特殊文本。\n  感兴趣的，可以看一下SpecialTextSpanBuilder里面build方法的实现，当然你也可以写出属于自己的build逻辑\n- createSpecialText 通过判断flag来判定是否是一个特殊文本\n\n```dart\nclass MySpecialTextSpanBuilder extends SpecialTextSpanBuilder {\n  MySpecialTextSpanBuilder({this.showAtBackground = false});\n\n  /// whether show background for @somebody\n  final bool showAtBackground;\n  @override\n  TextSpan build(String data,\n      {TextStyle textStyle, SpecialTextGestureTapCallback onTap}) {\n    if (kIsWeb) {\n      return TextSpan(text: data, style: textStyle);\n    }\n\n    return super.build(data, textStyle: textStyle, onTap: onTap);\n  }\n\n  @override\n  SpecialText createSpecialText(String flag,\n      {TextStyle textStyle, SpecialTextGestureTapCallback onTap, int index}) {\n    if (flag == null || flag == '') {\n      return null;\n    }\n\n    ///index is end index of start flag, so text start index should be index-(flag.length-1)\n    if (isStart(flag, AtText.flag)) {\n      return AtText(\n        textStyle,\n        onTap,\n        start: index - (AtText.flag.length - 1),\n        showAtBackground: showAtBackground,\n      );\n    } else if (isStart(flag, EmojiText.flag)) {\n      return EmojiText(textStyle, start: index - (EmojiText.flag.length - 1));\n    } else if (isStart(flag, DollarText.flag)) {\n      return DollarText(textStyle, onTap,\n          start: index - (DollarText.flag.length - 1));\n    }\n    return null;\n  }\n}\n```\n\n其实你也不是一定要用这套代码将字符串转换为TextSpan，你可以有自己的方法，给最后的TextSpan就可以了。\n\n\n## 图片\n\n![](https://github.com/fluttercandies/Flutter_Candies/blob/master/gif/extended_text/custom_image.gif)\n\n### ImageSpan\n\n使用ImageSpan 展示图片\n\n```dart\nImageSpan(\n    ImageProvider image, {\n    Key key,\n    @required double imageWidth,\n    @required double imageHeight,\n    EdgeInsets margin,\n    int start: 0,\n    ui.PlaceholderAlignment alignment = ui.PlaceholderAlignment.bottom,\n    String actualText,\n    TextBaseline baseline,\n    TextStyle style,\n    BoxFit fit: BoxFit.scaleDown,\n    ImageLoadingBuilder loadingBuilder,\n    ImageFrameBuilder frameBuilder,\n    String semanticLabel,\n    bool excludeFromSemantics = false,\n    Color color,\n    BlendMode colorBlendMode,\n    AlignmentGeometry imageAlignment = Alignment.center,\n    ImageRepeat repeat = ImageRepeat.noRepeat,\n    Rect centerSlice,\n    bool matchTextDirection = false,\n    bool gaplessPlayback = false,\n    FilterQuality filterQuality = FilterQuality.low,\n  })\n\n\nImageSpan(AssetImage(\"xxx.jpg\"),\n        imageWidth: size,\n        imageHeight: size,\n        margin: EdgeInsets.only(left: 2.0, bottom: 0.0, right: 2.0));\n  }\n```\n\n| 参数        | 描述                                                              | 默认             |\n| ----------- | ----------------------------------------------------------------- | ---------------- |\n| image       | 图片展示的Provider(ImageProvider)                                 | -                |\n| imageWidth  | 宽度，不包括 margin                                               | 必填             |\n| imageHeight | 高度，不包括 margin                                               | 必填             |\n| margin      | 图片的margin                                                      | -                |\n| actualText  | 真实的文本,当你开启文本选择功能的时候，必须设置,比如图片\"\\[love\\] | 空占位符'\\uFFFC' |\n| start       | 在文本字符串中的开始位置,当你开启文本选择功能的时候，必须设置     | 0                |\n\n## 文本选择\n\n现在它和 `SelectionArea` 一起工作。\n\n### 文本选择控制器\n\n \n你可以通过重写 [SelectionArea.contextMenuBuilder] 和 [TextSelectionControls]， 来定义工具栏和选择器\n\n```dart\nconst double _kHandleSize = 22.0;\n\n/// Android Material styled text selection controls.\n\nclass MyTextSelectionControls extends TextSelectionControls\n    with TextSelectionHandleControls {\n  MyTextSelectionControls({this.joinZeroWidthSpace = false});\n  final bool joinZeroWidthSpace;\n\n  /// Returns the size of the Material handle.\n  @override\n  Size getHandleSize(double textLineHeight) =\u003e\n      const Size(_kHandleSize, _kHandleSize);\n\n  /// Builder for material-style text selection handles.\n  @override\n  Widget buildHandle(\n      BuildContext context, TextSelectionHandleType type, double textLineHeight,\n      [VoidCallback? onTap, double? startGlyphHeight, double? endGlyphHeight]) {\n    final Widget handle = SizedBox(\n      width: _kHandleSize,\n      height: _kHandleSize,\n      child: Image.asset(\n        'assets/40.png',\n      ),\n    );\n\n    // [handle] is a circle, with a rectangle in the top left quadrant of that\n    // circle (an onion pointing to 10:30). We rotate [handle] to point\n    // straight up or up-right depending on the handle type.\n    switch (type) {\n      case TextSelectionHandleType.left: // points up-right\n        return Transform.rotate(\n          angle: math.pi / 4.0,\n          child: handle,\n        );\n      case TextSelectionHandleType.right: // points up-left\n        return Transform.rotate(\n          angle: -math.pi / 4.0,\n          child: handle,\n        );\n      case TextSelectionHandleType.collapsed: // points up\n        return handle;\n    }\n  }\n\n  /// Gets anchor for material-style text selection handles.\n  ///\n  /// See [TextSelectionControls.getHandleAnchor].\n  @override\n  Offset getHandleAnchor(TextSelectionHandleType type, double textLineHeight,\n      [double? startGlyphHeight, double? endGlyphHeight]) {\n    switch (type) {\n      case TextSelectionHandleType.left:\n        return const Offset(_kHandleSize, 0);\n      case TextSelectionHandleType.right:\n        return Offset.zero;\n      default:\n        return const Offset(_kHandleSize / 2, -4);\n    }\n  }\n}\n\nclass CommonSelectionArea extends StatelessWidget {\n  const CommonSelectionArea({\n    super.key,\n    required this.child,\n    this.joinZeroWidthSpace = false,\n  });\n  final Widget child;\n  final bool joinZeroWidthSpace;\n\n  @override\n  Widget build(BuildContext context) {\n    SelectedContent? _selectedContent;\n    return SelectionArea(\n      contextMenuBuilder:\n          (BuildContext context, SelectableRegionState selectableRegionState) {\n        return AdaptiveTextSelectionToolbar.buttonItems(\n          buttonItems: \u003cContextMenuButtonItem\u003e[\n            ContextMenuButtonItem(\n              onPressed: () {\n                // TODO(zmtzawqlp):  how to get Selectable\n                // and  _clearSelection is not public\n                // https://github.com/flutter/flutter/issues/126980\n\n                //  onCopy: () {\n                //   _copy();\n\n                //   // In Android copy should clear the selection.\n                //   switch (defaultTargetPlatform) {\n                //     case TargetPlatform.android:\n                //     case TargetPlatform.fuchsia:\n                //       _clearSelection();\n                //     case TargetPlatform.iOS:\n                //       hideToolbar(false);\n                //     case TargetPlatform.linux:\n                //     case TargetPlatform.macOS:\n                //     case TargetPlatform.windows:\n                //       hideToolbar();\n                //   }\n                // },\n\n                // if (_selectedContent != null) {\n                //   String content = _selectedContent!.plainText;\n                //   if (joinZeroWidthSpace) {\n                //     content = content.replaceAll(zeroWidthSpace, '');\n                //   }\n\n                //   Clipboard.setData(ClipboardData(text: content));\n                //   selectableRegionState.hideToolbar(true);\n                //   selectableRegionState._clearSelection();\n                // }\n\n                selectableRegionState\n                    .copySelection(SelectionChangedCause.toolbar);\n\n                // remove zeroWidthSpace\n                if (joinZeroWidthSpace) {\n                  Clipboard.getData('text/plain').then((ClipboardData? value) {\n                    if (value != null) {\n                      // remove zeroWidthSpace\n                      final String? plainText =\n                          value.text?.replaceAll(ExtendedTextLibraryUtils.zeroWidthSpace, '');\n                      if (plainText != null) {\n                        Clipboard.setData(ClipboardData(text: plainText));\n                      }\n                    }\n                  });\n                }\n              },\n              type: ContextMenuButtonType.copy,\n            ),\n            ContextMenuButtonItem(\n              onPressed: () {\n                selectableRegionState.selectAll(SelectionChangedCause.toolbar);\n              },\n              type: ContextMenuButtonType.selectAll,\n            ),\n            ContextMenuButtonItem(\n              onPressed: () {\n                launchUrl(Uri.parse(\n                    'mailto:zmtzawqlp@live.com?subject=extended_text_share\u0026body=${_selectedContent?.plainText}'));\n                selectableRegionState.hideToolbar();\n              },\n              type: ContextMenuButtonType.custom,\n              label: 'like',\n            ),\n          ],\n          anchors: selectableRegionState.contextMenuAnchors,\n        );\n        // return AdaptiveTextSelectionToolbar.selectableRegion(\n        //   selectableRegionState: selectableRegionState,\n        // );\n      },\n      // magnifierConfiguration: TextMagnifierConfiguration(\n      //   magnifierBuilder: (\n      //     BuildContext context,\n      //     MagnifierController controller,\n      //     ValueNotifier\u003cMagnifierInfo\u003e magnifierInfo,\n      //   ) {\n      //     return TextMagnifier(\n      //       magnifierInfo: magnifierInfo,\n      //     );\n      //     // switch (defaultTargetPlatform) {\n      //     //   case TargetPlatform.iOS:\n      //     //     return CupertinoTextMagnifier(\n      //     //       controller: controller,\n      //     //       magnifierInfo: magnifierInfo,\n      //     //     );\n      //     //   case TargetPlatform.android:\n      //     //     return TextMagnifier(\n      //     //       magnifierInfo: magnifierInfo,\n      //     //     );\n      //     //   case TargetPlatform.fuchsia:\n      //     //   case TargetPlatform.linux:\n      //     //   case TargetPlatform.macOS:\n      //     //   case TargetPlatform.windows:\n      //     //     return null;\n      //     // }\n      //   },\n      // ),\n      // selectionControls: MyTextSelectionControls(),\n      onSelectionChanged: (SelectedContent? value) {\n        print(value?.plainText);\n        _selectedContent = value;\n      },\n      child: child,\n    );\n  }\n}\n```\n\n \n## 自定义背景\n\n![](https://github.com/fluttercandies/Flutter_Candies/blob/master/gif/extended_text/background.png)\n\nText背景相关的issue[24335](https://github.com/flutter/flutter/issues/24335)/[24337](https://github.com/flutter/flutter/issues/24337)\n\n```dart\n  BackgroundTextSpan(\n      text:\n          \"This text has nice background with borderradius,no mattter how many line,it likes nice\",\n      background: Paint()..color = Colors.indigo,\n      clipBorderRadius: BorderRadius.all(Radius.circular(3.0))),\n```\n| 参数             | 描述                                       | 默认 |\n| ---------------- | ------------------------------------------ | ---- |\n| background       | 背景画刷                                   | -    |\n| clipBorderRadius | 用于裁剪背景                               | -    |\n| paintBackground  | 绘制背景的回调，你可以按照你的想法绘画背景 | -    |\n\n## 自定义文本溢出\n\n| ![](https://github.com/fluttercandies/Flutter_Candies/blob/master/gif/extended_text/overflow.jpg) | ![](https://github.com/HarmonyCandies/HarmonyCandies/blob/main/gif/extended_text/textOverflowPosition_auto.png) |\n| ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |\n|                                                                                                   |                                                                                                                 |\n\n文本溢出相关issue [26748](https://github.com/flutter/flutter/issues/26748)\n\n| parameter | description                                                           | default                  |\n| --------- | --------------------------------------------------------------------- | ------------------------ |\n| child     | The widget of TextOverflow.                                           | @required                |\n| maxHeight | Widget的最大高度，默认为 TextPaint计算出来的行高 preferredLineHeight. | preferredLineHeight      |\n| align     | left，靠近最后裁剪文本；right，靠近文本的右下角                       | right                    |\n| position  | 溢出文本出现的地方.                                                   | TextOverflowPosition.end |\n\n```dart\n  ExtendedText(\n   overflowWidget: TextOverflowWidget(\n     position: TextOverflowPosition.end,\n     align: TextOverflowAlign.center,\n     // just for debug\n     debugOverflowRectColor: Colors.red.withOpacity(0.1),\n     child: Container(\n       child: Row(\n         mainAxisSize: MainAxisSize.min,\n         children: \u003cWidget\u003e[\n           const Text('\\u2026 '),\n           InkWell(\n             child: const Text(\n               'more',\n             ),\n             onTap: () {\n               launch(\n                   'https://github.com/fluttercandies/extended_text');\n             },\n           )\n         ],\n       ),\n     ),\n   ),\n  )\n```\n\n## Join Zero-Width Space\n\n![](https://github.com/fluttercandies/Flutter_Candies/blob/master/gif/extended_text/JoinZeroWidthSpace.jpg)\n\n相关问题 [18761](https://github.com/flutter/flutter/issues/18761)\n\n如果[ExtendedText.joinZeroWidthSpace] 为 true, 将会添加'\\u{200B}' 到文本中, 让换行或者文本溢出看起来更好。\n\n```dart\n  ExtendedText(\n      joinZeroWidthSpace: true,\n    )\n```\n\n或者你也可以通过下面的方法自己转换\n\n1. 文本\n\n```dart\n  String input='abc'.joinChar();\n```\n\n2. InlineSpan\n\n```dart\n     InlineSpan innerTextSpan;\n     innerTextSpan = joinChar(\n        innerTextSpan,\n        Accumulator(),\n        zeroWidthSpace,\n    );\n```\n注意以下问题:\n\n1. word 不再是 word，你将无法通过双击选择 word。\n\n2. 文本被修改了, 你需要重写 TextSelectionControls，将字符串还原。\n\n``` dart\n\nclass MyTextSelectionControls extends TextSelectionControls {\n\n  @override\n  void handleCopy(TextSelectionDelegate delegate,\n      ClipboardStatusNotifier? clipboardStatus) {\n    final TextEditingValue value = delegate.textEditingValue;\n\n    String data = value.selection.textInside(value.text);\n    // remove zeroWidthSpace\n    data = data.replaceAll(zeroWidthSpace, '');\n\n    Clipboard.setData(ClipboardData(\n      text: value.selection.textInside(value.text),\n    ));\n    clipboardStatus?.update();\n    delegate.textEditingValue = TextEditingValue(\n      text: value.text,\n      selection: TextSelection.collapsed(offset: value.selection.end),\n    );\n    delegate.bringIntoView(delegate.textEditingValue.selection.extent);\n    delegate.hideToolbar();\n  }\n}\n\n```\n\n## Gradient\n\n### GradientConfig\n\n\n用于配置文本渐变的设置。\n\n* [gradient] 是要应用于文本的渐变效果。\n* [ignoreWidgetSpan] 决定是否将 WidgetSpan 元素包含在渐变应用中。默认情况下，WidgetSpan 被忽略。\n* [renderMode] 指定渐变应用于文本的方式。默认值为 [GradientRenderMode.fullText]，即将渐变应用于整个文本。\n* [ignoreRegex] 是一个正则表达式，用于排除文本中的某些部分，使其不受渐变效果影响。例如，可以用来排除特定字符或词语（如表情符号或特殊符号）以免它们受到渐变的影响。\n* [beforeDrawGradient] 在渐变被绘制到文本之前调用的回调函数。\n\n* [blendMode] 应用于渐变的混合模式。\n   默认值: [BlendMode.srcIn]（即渐变将应用于文本上）。\n   推荐使用 [BlendMode.srcIn] 或 [BlendMode.srcATop]。\n\n``` dart\n  GradientConfig _config = GradientConfig(\n    gradient: const LinearGradient(\n      colors: \u003cColor\u003e[Colors.blue, Colors.red],\n    ),\n    ignoreRegex: GradientConfig.ignoreEmojiRegex,\n    ignoreWidgetSpan: true,\n    renderMode: GradientRenderMode.fullText,\n  );\n```\n\n### IgnoreGradientSpan\n\n该 `InlineSpan` 将始终忽略渐变效果。\n\n``` dart\nclass IgnoreGradientTextSpan extends TextSpan with IgnoreGradientSpan {\n  IgnoreGradientTextSpan({String? text, List\u003cInlineSpan\u003e? children})\n      : super(\n          text: text,\n          children: children,\n        );\n}\n```\n\n\n\n## ☕️Buy me a coffee\n\n![img](http://zmtzawqlp.gitee.io/my_images/images/qrcode.png)\n","funding_links":["http://zmtzawqlp.gitee.io/my_images/images/qrcode.png"],"categories":["Dart"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Fextended_text","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluttercandies%2Fextended_text","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluttercandies%2Fextended_text/lists"}