Flutter实现Android的SpannableString,寻找所有符合条件字符串并上色

今天遇到一个需求,后台返回字符串和目标字符,将目标字符上色,在Android中很好实现,使用TextSpannableString就可以,但是Flutter中只能使用TextSpan,尝试了几种方法后终于实现。

import 'package:flutter/material.dart';
import 'package:easy_flutter/utils/extension/StringUtils.dart';

class SpannableTextWidget extends StatefulWidget {
  final String text;
  final List pattern;
  final TextStyle defStyle;
  final TextStyle patternStyle;
  final EdgeInsets margin;

  SpannableTextWidget(
      {this.text,
      this.pattern,
      this.defStyle,
      this.patternStyle,
      this.margin = EdgeInsets.zero});

  @override
  State createState() => _SpannableTextState();
}

class _SpannableTextState extends State {
  List list = [];
  List indexList = [];
  Map> _memory = {};
  int index = 0;

  @override
  void initState() {
    super.initState();
    String t = widget.text;
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _init(t);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: widget.margin,
      child: list.isEmpty
          ? Text('')
          : Text.rich(
              TextSpan(children: list),
            ),
    );
  }

  _init(String t) {
    if (t != null && t.isNotEmpty) {
      if (widget.pattern != null && widget.pattern.isNotEmpty) {
        widget.pattern.forEach((element) {
          if (_memory[element] == null) _memory[element] = [];
          while (_calc(t, element) != -1) {}
        });
      } else {
        list.add(TextSpan(text: t, style: widget.defStyle));
      }
      var charList = t.toCharList();
      for (int i = 0; i < charList.length; i++) {
        if (indexList.contains(i)) {
          list.add(TextSpan(text: charList[i], style: widget.patternStyle));
        } else
          list.add(TextSpan(text: charList[i], style: widget.defStyle));
      }
      setState(() {});
    }
  }

  int _calc(String t, String element) {
    int indexOf = t.indexOf(
        element, _memory[element].isEmpty ? 0 : _memory[element].last + 1);

    if (indexOf != -1) {

      for (int i = indexOf; i < indexOf + element.length; i++) {
        if (!indexList.contains(i)) indexList.add(i);
      }
      _memory[element].add(indexOf);
    }
    return indexOf;
  }
}
List toCharList() {
  return this.runes.map((e) => String.fromCharCode(e)).toList();
}

使用方法

SpannableTextWidget(
                      text: '11121222211133123453454353412312',
                      pattern: ["1", "3", "5"],
                      defStyle: TextStyle(
                          fontSize: 15, color: Colors.black),
                      patternStyle: TextStyle(fontSize:18,color:Colors.red),
                      margin:
                          EdgeInsets.only(top: 22, left: 20, right: 20),
                    )

运行效果


微信截图_20210922102428.png

刚发群里没多久,就被大佬教育了,说我写的太烂,然后大佬给出了自己的解决方案:

import 'package:flutter/material.dart';
import 'package:easy_flutter/utils/extension/StringUtils.dart';

class SpannableTextWidget extends StatelessWidget {
  final String text;
  final List pattern;
  final TextStyle defStyle;
  final TextStyle patternStyle;
  final EdgeInsets margin;

  SpannableTextWidget(
      {this.text,
      this.pattern,
      this.defStyle,
      this.patternStyle,
      this.margin = EdgeInsets.zero});

  @override
  Widget build(BuildContext context) {
    RegExp regExp = RegExp('$pattern');

    List list = text
        .replaceAllMapped(regExp, (match) => '&*${match[0]}&*')
        .split('&*')
        .map((e) => regExp.matchAsPrefix(e) == null
            ? TextSpan(text: e, style: defStyle)
            : TextSpan(text: e, style: patternStyle))
        .toList();

    return Container(
      margin: margin,
      child: list.isEmpty
          ? Text('')
          : Text.rich(
              TextSpan(children: list),
            ),
    );
  }
}

你可能感兴趣的:(Flutter实现Android的SpannableString,寻找所有符合条件字符串并上色)