如何在 SwiftUI 中使用 NSAttributedString 和 ScrollView?
Posted
技术标签:
【中文标题】如何在 SwiftUI 中使用 NSAttributedString 和 ScrollView?【英文标题】:How to use an NSAttributedString with a ScrollView in SwiftUI? 【发布时间】:2020-01-24 00:43:04 【问题描述】:我已经能够通过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
中工作?
【问题讨论】:
【参考方案1】:原因是 SwiftUI ScrollView
需要定义内容大小,但使用的 UITextView
本身是 UIScrollView
并根据父视图中的可用空间检测内容。因此,它发生了未定义大小的循环。
以下是解决此问题的可能方法的简化演示。这个想法是计算 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 !
【讨论】:
效果很好!我需要的一个小补充是将height
赋值包装在DispatchQueue.main.async
调用中,否则我会收到关于在渲染中设置状态的SwiftUI 警告,结果视图为空。【参考方案2】:
如果你想使用Asperi'sTextWithAttributedString
作为子视图,替换
height = textView.sizeThatFits(UIScreen.main.bounds.size).height
通过
DispatchQueue.main.async
height = textView.sizeThatFits(textView.visibleSize).height
【讨论】:
以上是关于如何在 SwiftUI 中使用 NSAttributedString 和 ScrollView?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中使用 SFSafariViewController?
如何在 SwiftUI 中使用 .fileimporter 保存音频文件并检索文件并在 SwiftUI 列表中显示它们的文件名?