flutter - 如何根据有效(@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 没有超链接,因为它不是有效的提及。
解决方案
据我了解,您想在字符串中突出显示主题标签和提及(预先存储在列表中)。
让我把它分成两部分,第一部分是从文本中提取主题标签和提及。
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;
}
推荐阅读
- typescript - 为什么 Webpack 延迟加载会加载文件夹中的所有文件?
- apache-spark - 在 Spark 数据帧中连续编号重复项而不进行随机播放
- javascript - 输入搜索在 JS 中被阻止
- java - 逆时针旋转矩阵 M*N 的每个环
- python - 在一秒钟内打印 40 条消息。打印件必须在一秒钟内均匀分布
- docker - 无法在 Windows 10 上的本地 Docker 中使用弹性搜索
- iteration - 遍历列表列表,每个列表包含 2 个项目
- ruby - 如何引发异常,将其作为参数发送给另一个方法,并在另一个方法中挽救异常?
- iframe - 使用 Svelte 访问 iframe 内容
- mysql - 在 SSMS 中创建链接服务器到远程服务器上的 MySQL 数据库