如何在 SwiftUI 中将 NSAttributedString 与 ScrollView 一起使用?
How to use an NSAttributedString with a ScrollView in SwiftUI?
我已经能够通过 UIViewRepresentable
渲染 NSAttributedString
s,在我将视图包装在 ScrollView
之前效果很好。
当放置在 ScrollView
内时,NSAttributedString
视图停止渲染。
我尝试了一些其他方法,将 NSAttributedString
替换为将多个 Text()
视图添加在一起,以获得在 ScrollView
内工作并支持 斜体的格式 和 monospace font
。不幸的是,这对文本块内的 links 不起作用,这意味着我仍然需要一个 NSAttributedString
.
import SwiftUI
struct TextWithAttributedString: UIViewRepresentable {
var attributedString: NSAttributedString
init(_ attributedString: NSAttributedString) {
self.attributedString = attributedString
}
func makeUIView(context: Context) -> UITextView {
let textView = UITextView(frame: .zero)
textView.attributedText = self.attributedString
textView.isEditable = false
return textView
}
func updateUIView(_ textView: UITextView, context: Context) {
textView.attributedText = self.attributedString
}
}
let exampleText = """
Fugiat id blanditiis et est culpa voluptas. Vivamus aliquet enim eu blandit blandit. Sit eget praesentium maxime sit molestiae et alias aut.
"""
struct NSAttributedStringView: View {
var body: some View {
// Note: when uncommented, the view breaks
// ScrollView {
TextWithAttributedString(NSAttributedString(string: exampleText))
// }
}
}
struct NSAttributedStringView_Previews: PreviewProvider {
static var previews: some View {
NSAttributedStringView()
.previewLayout(.sizeThatFits)
}
}
编辑: 我尝试使用 UITextView
和 text
属性 集而不是 attributeText
属性,但这也无法在 ScrollView
中呈现,因此问题似乎是 UITextView
,而不是 NSAttributedString
。
所以问题是,我们如何让 UITextView
在 ScrollView
中工作?
原因是 SwiftUI ScrollView
需要定义内容大小,但使用的 UITextView
本身就是 UIScrollView
并根据父视图中的可用 space 检测内容。因此它发生了未定义大小的循环。
这是解决此问题的可能方法的简化演示。这个想法是计算 UITextView
的内容大小并将其传递给 SwiftUI...
struct TextWithAttributedString: UIViewRepresentable {
@Binding var height: CGFloat
var attributedString: NSAttributedString
func makeUIView(context: Context) -> UITextView {
let textView = UITextView(frame: .zero)
textView.isEditable = false
return textView
}
func updateUIView(_ textView: UITextView, context: Context) {
textView.attributedText = self.attributedString
// calculate height based on main screen, but this might be
// improved for more generic cases
DispatchQueue.main.async { // << fixed
height = textView.sizeThatFits(UIScreen.main.bounds.size).height
}
}
}
struct NSAttributedStringView: View {
@State private var textHeight: CGFloat = .zero
var body: some View {
ScrollView {
TextWithAttributedString(height: $textHeight, attributedString: NSAttributedString(string: exampleText))
.frame(height: textHeight) // << specify height explicitly !
}
}
}
如果您想使用 TextWithAttributedString
作为子视图,请替换
height = textView.sizeThatFits(UIScreen.main.bounds.size).height
来自
DispatchQueue.main.async {
height = textView.sizeThatFits(textView.visibleSize).height
}
我已经能够通过 UIViewRepresentable
渲染 NSAttributedString
s,在我将视图包装在 ScrollView
之前效果很好。
当放置在 ScrollView
内时,NSAttributedString
视图停止渲染。
我尝试了一些其他方法,将 NSAttributedString
替换为将多个 Text()
视图添加在一起,以获得在 ScrollView
内工作并支持 斜体的格式 和 monospace font
。不幸的是,这对文本块内的 links 不起作用,这意味着我仍然需要一个 NSAttributedString
.
import SwiftUI
struct TextWithAttributedString: UIViewRepresentable {
var attributedString: NSAttributedString
init(_ attributedString: NSAttributedString) {
self.attributedString = attributedString
}
func makeUIView(context: Context) -> UITextView {
let textView = UITextView(frame: .zero)
textView.attributedText = self.attributedString
textView.isEditable = false
return textView
}
func updateUIView(_ textView: UITextView, context: Context) {
textView.attributedText = self.attributedString
}
}
let exampleText = """
Fugiat id blanditiis et est culpa voluptas. Vivamus aliquet enim eu blandit blandit. Sit eget praesentium maxime sit molestiae et alias aut.
"""
struct NSAttributedStringView: View {
var body: some View {
// Note: when uncommented, the view breaks
// ScrollView {
TextWithAttributedString(NSAttributedString(string: exampleText))
// }
}
}
struct NSAttributedStringView_Previews: PreviewProvider {
static var previews: some View {
NSAttributedStringView()
.previewLayout(.sizeThatFits)
}
}
编辑: 我尝试使用 UITextView
和 text
属性 集而不是 attributeText
属性,但这也无法在 ScrollView
中呈现,因此问题似乎是 UITextView
,而不是 NSAttributedString
。
所以问题是,我们如何让 UITextView
在 ScrollView
中工作?
原因是 SwiftUI ScrollView
需要定义内容大小,但使用的 UITextView
本身就是 UIScrollView
并根据父视图中的可用 space 检测内容。因此它发生了未定义大小的循环。
这是解决此问题的可能方法的简化演示。这个想法是计算 UITextView
的内容大小并将其传递给 SwiftUI...
struct TextWithAttributedString: UIViewRepresentable {
@Binding var height: CGFloat
var attributedString: NSAttributedString
func makeUIView(context: Context) -> UITextView {
let textView = UITextView(frame: .zero)
textView.isEditable = false
return textView
}
func updateUIView(_ textView: UITextView, context: Context) {
textView.attributedText = self.attributedString
// calculate height based on main screen, but this might be
// improved for more generic cases
DispatchQueue.main.async { // << fixed
height = textView.sizeThatFits(UIScreen.main.bounds.size).height
}
}
}
struct NSAttributedStringView: View {
@State private var textHeight: CGFloat = .zero
var body: some View {
ScrollView {
TextWithAttributedString(height: $textHeight, attributedString: NSAttributedString(string: exampleText))
.frame(height: textHeight) // << specify height explicitly !
}
}
}
如果您想使用 TextWithAttributedString
作为子视图,请替换
height = textView.sizeThatFits(UIScreen.main.bounds.size).height
来自
DispatchQueue.main.async {
height = textView.sizeThatFits(textView.visibleSize).height
}