就在 swiftUI 中渲染 HTML 而言,有很多解决方案,但对于通过 AttributedText 将其渲染为通用 UILabel,这是我在结合我找到的其他一些解决方案后所采用的。
这是您将从父 swiftUI 视图中使用的 UIViewRepresentable:
//Pass in your htmlstring, and the maximum width that you are allowing for the label
//this will, in turn, pass back the size of the newly created label via the binding 'size' variable
//you must use the new size variable frame on an encompassing view of wherever this htmlAttributedLabel now resides (like in an hstack, etc.)
struct htmlAttributedLabel: UIViewRepresentable {
@Binding var htmlText: String
var width: CGFloat
@Binding var size:CGSize
var lineLimit = 0
//var textColor = Color(.label)
func makeUIView(context: Context) -> UILabel {
let label = UILabel()
label.lineBreakMode = .byWordWrapping
label.numberOfLines = lineLimit
label.preferredMaxLayoutWidth = width
//label.textColor = textColor.uiColor()
return label
}
func updateUIView(_ uiView: UILabel, context: Context) {
let htmlData = NSString(string: htmlText).data(using: String.Encoding.unicode.rawValue)
let options = [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html]
DispatchQueue.main.async {
do {
let attributedString = try NSMutableAttributedString(data: htmlData!, options: options, documentAttributes: nil)
//add attributedstring attributes here if you want
uiView.attributedText = attributedString
size = uiView.sizeThatFits(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude))
print("htmlAttributedLabel size: \(size)")
} catch {
print("htmlAttributedLabel unexpected error: \(error).")
}
}
}
现在,要有效地使用此标签,您需要为其提供一个最大宽度,您可以从几何阅读器中获得该宽度。您还需要传入一个 CGSize 绑定,以便标签可以告诉父视图它需要渲染多少空间。反过来,您将使用此大小设置包含视图的高度,以便 swiftUI 的其余部分可以适当地围绕您的 html 标签进行布局:
@State var htmlText = "Hello,<br />I am <b>HTML</b>!"
@State var size:CGSize = .zero
var body: some View {
HStack {
GeometryReader { geometry in
htmlAttributedLabel(htmlText: $htmlText, width: geometry.size.width, size: $size).frame(width:size.width, height: size.height). //the frame is important to set here, otherwise sometimes it won't render right on repeat loads, depending on how this view is presented
}
}.frame(height: size.height) //most important, otherwise swiftui won't really know how to layout things around your attributed label
}
您还可以设置行限制或文本颜色等,显然您可以扩展此对象以接收您想要使用的任何 UIlabel 参数。