我正在使用一个NSTextView
inside NSViewRepresentable
在 SwiftUI 应用程序中。
The NSViewRepresentable
正确调整大小到 NSTextView 的高度,因此文本会流向多行,但在创建后的第一次渲染中,它只显示一行.
看来NSTextView
在第一帧上正确渲染,文本换行在正确的位置,但是NSViewRepresentable
不显示完整高度。
The NSTextView
已创建,并且文本设置为NSTextStorage
in the makeCoordinator()
的方法NSViewRepresentable
,即之前NSViewRepresentable
请求查看。
我覆盖NSTextView
设置intrinsicContentSize
:
override func layout() {
invalidateIntrinsicContentSize()
super.layout()
}
override var intrinsicContentSize: NSSize {
layoutManager!.ensureLayout(for: textContainer!)
return CGSize(width: -1.0,
height: ceil(layoutManager!.usedRect(for: textContainer!).size.height))
}
我认为这个问题是由中提到的“bobble”暗示的这个帖子 https://stackoverflow.com/a/63144255/978300。高度跟踪方法不同,但也无法设置第一帧。
我能做些什么来更快地强制布局NSTextView
?视图的宽度不固定,因此需要动态流动。
这是一个最小的再现:
import SwiftUI
let font = NSFont.systemFont(ofSize: 20, weight: .bold)
let testString = "This long string demonstrates how its full extent is not shown on the first frame of an NSTextView rendered within an NSViewRepresentable."
let fontAttribute = [NSAttributedString.Key.font: font]
let testText = NSAttributedString(string: testString, attributes: fontAttribute)
class InternalTextView: NSTextView
{
init() {
super.init(frame: NSRect.zero)
setContentHuggingPriority(.defaultHigh, for: .vertical)
}
override init(frame frameRect: NSRect, textContainer container: NSTextContainer?) {
super.init(frame: frameRect, textContainer: container) }
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func layout() {
invalidateIntrinsicContentSize()
super.layout()
}
override var intrinsicContentSize: NSSize {
layoutManager!.ensureLayout(for: textContainer!)
return CGSize(width: -1.0,
height: ceil(layoutManager!.usedRect(for: textContainer!).size.height))
}
}
class TextViewCoordinator: NSObject {
private(set) var view: InternalTextView
init(withText text: NSAttributedString) {
view = InternalTextView()
view.textStorage?.setAttributedString(text)
super.init()
}
}
struct TextView: NSViewRepresentable
{
let text: NSAttributedString
func makeNSView(context: Context) -> NSTextView { context.coordinator.view }
func updateNSView(_ nsView: NSTextView, context: Context) { }
func makeCoordinator() -> TextViewCoordinator { TextViewCoordinator(withText: text) }
}
struct ContentView: View
{
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State var showText: Bool = false
var body: some View {
HStack {
Spacer()
ScrollView {
VStack {
if showText {
ForEach(1..<10) { _ in
TextView(text: testText)
} }
Spacer()
}.frame(maxWidth: 600)
}
Spacer()
}
.onReceive(timer) { _ in
showText.toggle()
}
}
}
Frame 1:
Frame 2: