首页 > 解决方案 > 如何根据有效(@mentions)和所有主题标签更改文本颜色?

问题描述

我想在文本中以不同颜色显示主题标签和有效提及。


我得到了这段代码的帮助,它只适用于主题标签

RichText _convertHashtag(String text) {
  List<String> split = text.split(RegExp("#"));
  List<String> hashtags = split.getRange(1, split.length).fold([], (t, e) {
    var texts = e.split(" ");
    if (texts.length > 1) {
      return List.from(t)
        ..addAll(["#${texts.first}", "${e.substring(texts.first.length)}"]);
    }
    return List.from(t)..add("#${texts.first}");
  });
  return RichText(
    text: TextSpan(
      children: [TextSpan(text: split.first)]..addAll(hashtags
          .map((text) => text.contains("#")
              ? TextSpan(text: text, style: TextStyle(color: Colors.blue))
              : TextSpan(text: text))
          .toList()),
    ),
  );
}

我修改它像:


  List valid_mentions = ['@mention1', '@mention2'];//these are the valid mention

  RichText _convertHashtag(String text) {
    List<String> split = text.split(RegExp("#|@"));
    List<String> hashtags = split.getRange(1, split.length).fold([], (t, e) {
      var texts = e.split(" ");

      //here adding `@` sign and `#` sign to the given texts and storing them in the `hashtags` list
      if (texts.length > 1) {
        if (valid_mentions.contains(texts.first))
          return List.from(t)
            ..addAll(["@${texts.first}", "${e.substring(texts.first.length)}"]);
        else if (text.contains('@${texts.first}')) {
          return List.from(t)
            ..addAll(["@${texts.first}", "${e.substring(texts.first.length)}"]);
        } else
          return List.from(t)
            ..addAll(["#${texts.first}", "${e.substring(texts.first.length)}"]);
      } else {
        if (valid_mentions.contains(texts.first))
          return List.from(t)..addAll(["@${texts.first}"]);
        else if (text.contains('@${texts.first}')) {
          return List.from(t)..addAll(["@${texts.first}"]);
        } else
          return List.from(t)..addAll(["#${texts.first}"]);
      }
    });
    return RichText(
      text: TextSpan(
        children: [TextSpan(text: split.first)]..addAll(hashtags.map((text) {
            return text.contains("@")
                ? valid_mentions.contains(text)
                    ? //checking if the mention is valid
                    TextSpan(
                        text: text,
                        recognizer: TapGestureRecognizer()
                          ..onTap = () {
                            print(text);
                          },
                        style: TextStyle(color: Colors.blue))
                    : TextSpan(
                        text: text,
                      )
                : text.contains("#")
                    ? TextSpan(
                        text: text,
                        recognizer: TapGestureRecognizer()
                          ..onTap = () {
                            print(text);
                          },
                        style: TextStyle(color: Colors.blue))
                    : TextSpan(
                        text: text,
                      );
          }).toList()),
      ),
    );
  }

我能够进行所需的更改,但我相信它不是一种优化的方式,并且有很多样板代码。我该如何优化它?

输入:“我爱#flutter #android @mention1 @mention2 @mention3”

输出:“我爱#flutter #android @mention1 @mention2 @mention3”

这里@mention3 没有超链接,因为它不是有效的提及。

标签: flutterdartdart-pub

解决方案


据我了解,您想在字符串中突出显示主题标签和提及(预先存储在列表中)。

让我把它分成两部分,第一部分是从文本中提取主题标签和提及。

List<String> getAllHashtags(String text) {
  final regexp = RegExp(r'\#[a-zA-Z0-9]+\b()');

  List<String> hashtags = [];

  regexp.allMatches(text).forEach((element) {
    if (element.group(0) != null) {
      hashtags.add(element.group(0).toString());
    }
  });

  return hashtags;
}

List<String> getAllMentions(String text) {
  final regexp = RegExp(r'\@[a-zA-Z0-9]+\b()');

  List<String> mentions = [];

  regexp.allMatches(text).forEach((element) {
    if (element.group(0) != null) {
      mentions.add(element.group(0).toString());
    }
  });

  return mentions;
}

上面的代码片段将成功地从给定的句子中提取主题标签和提及,并将其作为列表返回。

下一步是使用不同的 TextSpan 构建 RichText。

RichText buildHighlightedText(String text) {
  // clean the text
  text = cleanText(text);

  List<String> validMentions = ["@mention1", "@mention2"];
  
  List<String> hashtags = getAllHashtags(text);
  List<String> mentions = getAllMentions(text);

  List<TextSpan> textSpans = [];

  text.split(" ").forEach((value) {
    if (hashtags.contains(value)) {
      textSpans.add(TextSpan(
        text: '$value ',
        style: TextStyle(color: Colors.amber, fontWeight: FontWeight.bold),
      ));
    } else if (mentions.contains(value) && validMentions.contains(value)) {
      textSpans.add(TextSpan(
        text: '$value ',
        style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
      ));
    } else {
      textSpans.add(TextSpan(text: '$value '));
    }
  });

  return RichText(text: TextSpan(children: textSpans));
}

文本已被空格分隔,并过滤主题标签/提及并为每个返回不同样式的 TextSpan。这是一种更简洁、更干净的方式来做你正在寻找的事情。

这是一个例子:

通过示例运行应用程序

编辑:

为了解析没有空格的主题标签,我们需要在每个实例前面添加一个空格。

String cleanText(String text) {
  text = text.replaceAllMapped(
      RegExp(r'\w#+'), (Match m) => "${m[0]?.split('').join(" ")}");

  text = text.replaceAllMapped(
      RegExp(r'\w@+'), (Match m) => "${m[0]?.split('').join(" ")}");

  return text;
}

推荐阅读