flutter 简化处理RichText

453 阅读1分钟

原文地址:juejin.cn/post/735165…

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:tuple/tuple.dart';

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",
    void Function(String textTap)? onLink,
  }) {
    final pattern = textTaps.map((d) => RegExp.escape(d)).join('|');
    final regExp = RegExp(pattern, multiLine: true, caseSensitive: false);
    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) ||
            textTaps.contains(e.toLowerCase()) ||
            textTaps.contains(e.toUpperCase());
        if (isEquel) {
          return TextSpan(
            text: e,
            style: linkStyle ?? TextStyle(color: Colors.blue),
            recognizer: onLink == null ? null : TapGestureRecognizer()
              ?..onTap = () {
                onLink?.call(e);
              },
          );
        }
      }
      return TextSpan(text: e, style: style);
    }).toList();
  }
}

extension TextSpanExt on TextSpan {
  /// 二次赋值
  TextSpan copyWith({
    String? text,
    List<InlineSpan>? children,
    TextStyle? style,
    GestureRecognizer? recognizer,
    PointerEnterEventListener? onEnter,
    PointerExitEventListener? onExit,
    String? semanticsLabel,
    Locale? locale,
    bool? spellOut,
    ValueChanged<String?>? onLink,
  }) {
    final content = text ?? this.text;

    TapGestureRecognizer? gesture;
    if (onLink != null) {
      gesture = TapGestureRecognizer()..onTap = () => onLink.call(content);
    }

    return TextSpan(
      text: content,
      children: children ?? this.children,
      style: style ?? this.style,
      recognizer: gesture ?? recognizer ?? this.recognizer,
      onEnter: onEnter ?? this.onEnter,
      onExit: onExit ?? this.onExit,
      semanticsLabel: semanticsLabel ?? this.semanticsLabel,
      locale: locale ?? this.locale,
      spellOut: spellOut ?? this.spellOut,
    );
  }
}

知识点:

1 RegExp.escape(d) 这个函数的主要作用是用于转义正则表达式特殊字符。比如

/// print(RegExp.escape('dash@example.com')); // dash@example.com
/// print(RegExp.escape('a+b')); // a+b
/// print(RegExp.escape('a*b')); // a*b
/// print(RegExp.escape('{a-b}')); // {a-b}
/// print(RegExp.escape('a?')); // a?

2 RegExp(pattern, multiLine: true, caseSensitive: false); multiLine 多行匹配 caseSensitive 是否忽略大小写

3 splitMapJoin

  final textNew = text.splitMapJoin(
      regExp,
      //匹配到的内容替换成返回值
      onMatch: (m) => '$prefix${m[0]}$suffix', // (or no onMatch at all)
      //未匹配到的返回原本的值
      onNonMatch: (n) => n,
    );