要将HTML转换为TextWidget,您可以使用html包。以下是一个示例:
首先添加依赖项
dependencies:
flutter:
sdk: flutter
html: ^0.15.0
url_launcher: ^6.1.10
然后导入包并使用解析方法将HTML字符串转换为文档对象:
import 'package:flutter/material.dart';
import 'package:html/parser.dart' show parse;
import 'package:html/dom.dart' as dom;
import 'package:url_launcher/url_launcher.dart';
class HtmlToRichTextWidget extends StatelessWidget {
final String? htmlString;
const HtmlToRichTextWidget({Key? key, this.htmlString = ''})
: super(key: key);
@override
Widget build(BuildContext context) {
final document = html_parser.parse(htmlString);
final inlineSpans = _parseNode(document.body!);
return RichText(
text: TextSpan(
children: inlineSpans, style: const TextStyle(color: Colors.black)),
);
}
List<InlineSpan> _parseNode(dom.Node node) {
final inlineSpans = <InlineSpan>[];
if (node.nodeType == dom.Node.TEXT_NODE) {
final text = node.text;
inlineSpans.add(TextSpan(text: text));
} else if (node.nodeType == dom.Node.ELEMENT_NODE) {
final element = node as dom.Element;
switch (element.localName) {
case "b":
case 'strong':
return _parseElements(
element, const TextStyle(fontWeight: FontWeight.bold));
case "i":
case 'em':
return _parseElements(
element, const TextStyle(fontStyle: FontStyle.italic));
case "u":
return _parseElements(
element, const TextStyle(decoration: TextDecoration.underline));
case "sub":
inlineSpans.add(WidgetSpan(
alignment: PlaceholderAlignment.bottom,
child: SizedBox(
height: 10,
child: Text(
element.text,
style: const TextStyle(
fontSize: 12,
color: Colors.blue,
textBaseline: TextBaseline.alphabetic,
),
),
),
));
break;
case "sup":
inlineSpans.add(WidgetSpan(
alignment: PlaceholderAlignment.top,
child: SizedBox(
height: 10,
child: Text(
element.text,
style: const TextStyle(
fontSize: 12,
color: Colors.blue,
textBaseline: TextBaseline.alphabetic,
),
),
),
));
break;
case "p":
return _parseElements(element, const TextStyle());
case "span":
return _parseElements(element, const TextStyle(color: Colors.red));
case "a":
final href = element.attributes['href'] ?? '';
return _parseElements(
element,
const TextStyle(
decoration: TextDecoration.underline, color: Colors.blue),
href);
case 'br':
inlineSpans.add(const TextSpan(text: "\n"));
break;
default:
return _parseElements(element, const TextStyle());
}
}
return inlineSpans;
}
List<InlineSpan> _parseElements(dom.Element element, TextStyle style,
[String? href]) {
final spans = <InlineSpan>[];
for (final node in element.nodes) {
final childTextSpans = _parseNode(node);
for (final childTextSpan in childTextSpans) {
var launch = TapGestureRecognizer()
..onTap = () => launchUrl(Uri.tryParse(href ?? "")!);
if (childTextSpan is TextSpan) {
spans.add(
TextSpan(
text: childTextSpan.text,
style: style.merge(childTextSpan.style),
recognizer: href != null ? launch : null,
),
);
} else {
spans.add(childTextSpan);
print(childTextSpan.toString());
}
}
}
return spans;
}
}
在更新的版本中,我们在_parseNode方法中添加了对switch语句标签的支持。我们还更新了_parseElements方法,以接受可选的href参数,当遇到标签时,我们使用它来创建TapGestureRecognizer并添加到TextSpan中。
您需要从
url_launcher包中导入
package:flutter/gestures.dart
和
package:url_launcher/url_launcher.dart
,以使用TapGestureRecognizer和launch函数。
该插件不支持完整的HTML代码渲染
。 - shadowsheep