一、需求来源

工作中常常遇到一些富文本的款式,每次写许多的 TextSpan 的不胜其烦;今天总算想到一种完美处理高亮文本款式和阶段款式的办法,中心是经过 splitMapJoin 方法合作 RegExp,代码极其精简,运用极度舒适。

二、运用对比

1、原始代码

Text.rich(
    TextSpan(
      children: [
        TextSpan(
            text: "一般文本1",
            style: const TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w500,
              color: Color(0xFF1A1A1A),
            ),
        ),
        TextSpan(
            text: "高亮1",
            style: const TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w500,
              color: Color(0xFF737373),
            ),
        ),
         TextSpan(
            text: "一般文本2",
            style: const TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w500,
              color: Color(0xFF737373),
            ),
        ),
        TextSpan(
            text: "高亮2",
            style: const TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w500,
              color: Color(0xFF737373),
            ),
        ),
         TextSpan(
            text: "一般文本3",
            style: const TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w500,
              color: Color(0xFF737373),
            ),
        ),
      ],
    ),
  ),

2、封装后代码

final text = "一般文本1高亮1一般文本2高亮2一般文本3高亮3一般文本4";
final textTaps = ["高亮1", "高亮2", "高亮3"];
...
Text.rich(
  TextSpan(
    children: RichTextExt.createTextSpans(
      text: text,
      textTaps: textTaps,
      // linkStyle: TextStyle(fontSize: 18.0, color: Colors.red),
      onLink: (textTap) {
        ddlog(textTap);
      },
    ),
  ),
),

三、完成源码(35 行)

extension RichTextExt on RichText {
  /// 创建 List<TextSpan>
  ///
  /// text 整个阶段
  /// textTaps 高亮字符串数组
  /// style 阶段款式
  /// linkStyle 高亮款式
  /// prefix 切割符号,避免和文章包括字符串重复
  /// suffix 切割符号,避免和文章包括字符串重复
  /// onLink 高亮部分点击事件
  static List<TextSpan> createTextSpans({
    required String text,
    required List<String> textTaps,
    TextStyle? style,
    TextStyle? linkStyle,
    String prefix = "_&t",
    String suffix = "_&t",
    required void Function(String textTap) onLink,
  }) {
    final pattern = textTaps.map((d) => RegExp.escape(d)).join('|');
    final regExp = RegExp(pattern, multiLine: true);
    final textNew = text.splitMapJoin(regExp,
      onMatch: (m) => '$prefix${m[0]}$suffix', // (or no onMatch at all)
      onNonMatch: (n) => n,
    );
    final list = textNew.split(RegExp('$prefix|$suffix'));
    return list.map((e) {
      if (e.isNotEmpty) {
        final isEquel = textTaps.contains(e);
        if (isEquel) {
          return TextSpan(
            text: e,
            style: linkStyle ?? TextStyle(color: Colors.blue),
            recognizer: TapGestureRecognizer()
              ..onTap = () {
                onLink(e);
              },
          );
        }
      }
      return TextSpan(text: e, style: style);
    }).toList();
  }
}

四、总结

1、现在没有找比这更加高雅的,同时支撑高亮文本点击事件的代码完成,完全是灵光一闪的杰作。(如果有,请一定联络我!!!)
2、onLink 是高亮文本点击回调,引荐开端用一个Map保存高亮文字和对应的链接;例如:
var linkMap = {
  '《用户协议》': 'https://flutter.dev',
  '《隐私政策》': 'https://flutter.dev',
};
Text.rich(
  TextSpan(
    children: RichTextExt.createTextSpans(
      text: text,
      textTaps: linkMap.keys.toList(),
      // linkStyle: TextStyle(fontSize: 18.0, color: Colors.red),
      onLink: (textTap) {
        ddlog(textTap);// linkMap[textTap]即为相对应的协议链接
      },
    ),
  ),
),
3、原创便是开心啦啦啦。

github