【发布时间】:2020-02-27 15:50:57
【问题描述】:
我正在通过 UIViewRepresentable 为 SwiftUI 构建自定义 UITextView。它旨在显示NSAttributedString,并处理链接按下。一切正常,但是当我在带有内联标题的 NavigationView 中显示此视图时,框架高度完全混乱了。
import SwiftUI
struct AttributedText: UIViewRepresentable {
class Coordinator: NSObject, UITextViewDelegate {
var parent: AttributedText
init(_ view: AttributedText) {
parent = view
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
parent.linkPressed(URL)
return false
}
}
let content: NSAttributedString
@Binding var height: CGFloat
var linkPressed: (URL) -> Void
public func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.backgroundColor = .clear
textView.isEditable = false
textView.isUserInteractionEnabled = true
textView.delegate = context.coordinator
textView.isScrollEnabled = false
textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
textView.dataDetectorTypes = .link
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 0
return textView
}
public func updateUIView(_ view: UITextView, context: Context) {
view.attributedText = content
// Compute the desired height for the content
let fixedWidth = view.frame.size.width
let newSize = view.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
DispatchQueue.main.async {
self.height = newSize.height
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
struct ContentView: View {
private var text: NSAttributedString {
NSAttributedString(string: "Eartheart is the principal settlement for the Gold Dwarves in East Rift and it is still the cultural and spiritual center for its people. Dwarves take on pilgrimages to behold the great holy city and take their trips from other countries and the deeps to reach their goal, it use to house great temples and shrines to all the Dwarven pantheon and dwarf heroes but after the great collapse much was lost.\n\nThe lords of their old homes relocated here as well the Deep Lords. The old ways of the Deep Lords are still the same as they use intermediaries and masking themselves to undermine the attempts of assassins or drow infiltrators. The Gold Dwarves outnumber every other race in the city and therefor have full control of the city and it's communities.")
}
@State private var height: CGFloat = .zero
var body: some View {
NavigationView {
List {
AttributedText(content: text, height: $height, linkPressed: { url in print(url) })
.frame(height: height)
Text("Hello world")
}
.listStyle(GroupedListStyle())
.navigationBarTitle(Text("Content"), displayMode: .inline)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
当您运行此代码时,您会看到AttributedText 单元格太小而无法容纳其内容。
当您从navigationBarTitle 中删除displayMode: .inline 参数时,它显示正常。
但如果我添加另一行来显示高度值 (Text("\(height)")),它会再次中断。
也许这是某种由视图更新通过状态更改触发的竞争条件? height 值本身是正确的,只是框架实际上并没有那么高。有解决办法吗?
使用ScrollView 和VStack 确实可以解决问题,但由于内容在真实应用中的显示方式,我真的更喜欢使用List。
【问题讨论】: