rich_text_replace.dart 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import 'package:flutter/material.dart';
  2. class RichTextReplace extends StatelessWidget {
  3. final String text;
  4. final Map<String, String>? items;
  5. final TextStyle? defaultStyle;
  6. final TextStyle? replacedStyle;
  7. const RichTextReplace({
  8. super.key,
  9. required this.text,
  10. this.items,
  11. this.defaultStyle,
  12. this.replacedStyle,
  13. });
  14. @override
  15. Widget build(BuildContext context) {
  16. final spans = _buildTextSpans(
  17. text,
  18. items ?? {}, // 如果为空,传空 map
  19. );
  20. return RichText(
  21. text: TextSpan(
  22. children: spans,
  23. style: defaultStyle ?? DefaultTextStyle.of(context).style,
  24. ),
  25. );
  26. }
  27. List<InlineSpan> _buildTextSpans(
  28. String text, Map<String, String> replaceMap) {
  29. final List<InlineSpan> spans = [];
  30. int currentIndex = 0;
  31. final regex = RegExp(r'\$\{(.*?)\}');
  32. for (final match in regex.allMatches(text)) {
  33. final fullKey = match.group(0)!; // e.g. ${unlockCount}
  34. final key = match.group(1)!; // e.g. unlockCount
  35. // 普通文本部分
  36. if (match.start > currentIndex) {
  37. spans.add(TextSpan(text: text.substring(currentIndex, match.start)));
  38. }
  39. // 替换值(优先使用 ${key} 匹配,兼容性更好)
  40. final replaced = replaceMap[fullKey] ?? replaceMap[key] ?? '';
  41. // 加粗或自定义样式的替换值
  42. spans.add(TextSpan(
  43. text: replaced,
  44. style: replacedStyle ?? const TextStyle(fontWeight: FontWeight.bold),
  45. ));
  46. currentIndex = match.end;
  47. }
  48. // 尾部普通文本
  49. if (currentIndex < text.length) {
  50. spans.add(TextSpan(text: text.substring(currentIndex)));
  51. }
  52. return spans;
  53. }
  54. }