首页 > 解决方案 > 以编程方式突出显示 Flutter Richtext 中的字符串匹配项

问题描述

我有一个字符串,其中包含带有@标签的提及,我想创建一个富文本,其中每个标签都包含在带有用户名和 userIds 的提及地图中,并突出显示并使其可点击。

// dummy class

class Reply {
  List<dynamic> mentions;
  String? text;
  Reply({required this.mentions, required this.text});
}

// sample reply

 Reply sample = Reply(
    mentions: [
      {'username': 'sampleUser1', 'userId': '0x123'},
      {'username': 'sampleUser2', 'userId': '0x321'}
    ],
    text: 'This text mentions @0x123 as well as @0x321',
  );

// replacing all matching ids with the respective usernames

 for (var ment in sample.mentions) {
    sample.text = sample.text!.replaceAll(ment['userId'], ment['username']);
  }

print(sample.text); // This text mentions @sampleUser1 as well as @sampleUser2

这就是我卡住的地方。我想创建一个富文本,以粗体突出显示文本中的用户名并使其可点击。

RichText(
  text: TextSpan(
      children: 'sample sample' /*sample.text goes here*/
          .split(' ') /*find words that start with '@' and include a username that can also be found in the list of mentions*/
          .map((word) => TextSpan(
              text: word + ' ',
              style: TextStyle(
                  fontWeight:
                      true /*condition if word is found in mentions*/
                          ? FontWeight.bold
                          : FontWeight.normal),
              recognizer: TapGestureRecognizer()
                ..onTap =
                    true /*condition if word is found in mentions*/
                        ? () {
                            /*do something*/
                          }
                        : () {
                            /*do nothing*/
                          }))
          .toList())),

任何帮助表示赞赏,我会继续尝试,并在我弄清楚时在这里更新。

标签: regexflutterdart

解决方案


感谢@pskink,我得到了它的工作。

 buildTextSpan(String s, List<dynamic>? mentions) {

    var regularStyle = //regular style
    var mentionStyle = //style with mentions

    List<InlineSpan> children = [];

//return regular text if no users have been mentioned
    if(mentions == null || mentions.isEmpty){
      children.add(TextSpan(text: s, style: regularStyle));
      return TextSpan(children: children);
    }

    s.splitMapJoin(
//only match strings that are prefixed with '@' 
//and are contained in the mentions-map at the 'userId'-key that is passed in
//join the regex with 'or' to include all mentions
      RegExp(mentions.map((e) => '@'+e['userId']!).join('|')),

//if there's a match, re-add the '@' and grab the username to the userId as provided by the mentions-map
//substring(1) to exclude the @-sign when looking up the value in the map
      onMatch: (Match match) {
        children.add(TextSpan(
          text: '@' + mentions.firstWhere((element) => element['userId'] == match[0]!.substring(1))['username']!,
          style: mentionStyle,
//app specific: navigate to user screen and pass the userId
          recognizer: TapGestureRecognizer()..onTap = () => //navigation logic));
//return empty string that will not be used but has to be returned due to null-safety
        return '';
//add regular textspan on no match
      },onNonMatch: (String text) {children.add(TextSpan(
          text: text,
          style: regularStyle
        ));
        return '';}
    );
    return TextSpan(children: children);
  }

推荐阅读