主要问题:
SwiftUI 的
Text()
无法在内部填充大量文本。如果文本有太多符号或字体太大,则会显示以下错误:
[Window] 警告:Window SwiftUI.AppKitWindow 0x13be8e970 在非活动应用程序的前面排序,并且可能在活动应用程序的窗口下方排序。 2023-08-19 22:48:49.743611 + 0300 Videq [83718:3987311] - [<_TtCOCV7SwiftUI11DisplayList11ViewUpdater8PlatformP33_65A81BD07F0108B0485D2E15DE104A7514CGDrawingLayer: 0x6000031d8e40>显示]:忽略虚假图层大小(479.000000,323046.000000),contentsScale 2.000000,后备存储大小(958.000000, 646092.000000) 2023-08-19 22:48:49.791437+0300 Videq[83718:3987311] Metal API 验证已启用
所以我需要使用
Text()
编写自定义
NSTextView
我的代码是:
import SwiftUI
import Cocoa
@available(OSX 11.0, *)
public struct AttributedText2: View {
@Binding var text: AttributedString
var nsText: Binding<NSAttributedString> {
Binding(get: { NSAttributedString(text) }, set: { _ in })
}
@State var width: CGFloat = 0
public var body: some View {
AttributedTextInternal(attributedString: nsText)
}
}
//@available(OSX 11.0, *)
//public struct AttributedText: View {
// @Binding var text: NSAttributedString
//
// public init(attributedString: Binding<NSAttributedString>) {
// _text = attributedString
// }
//
// public var body: some View {
// AttributedTextInternal(attributedString: $text)
// }
//}
@available(OSX 11.0, *)
public struct AttributedTextInternal: NSViewRepresentable {
@Binding var text: NSAttributedString
public init(attributedString: Binding<NSAttributedString>) {
_text = attributedString
}
public func makeNSView(context: Context) -> CustTextFld {
let textView = CustTextFld()
textView.setContent(text: text, makeNotEditable: true)
textView.backgroundColor = .clear
textView.layerContentsPlacement = .top
textView.layerContentsRedrawPolicy = .crossfade
return textView
}
public func updateNSView(_ textView: CustTextFld, context: Context) {
textView.setContent(text: text, makeNotEditable: true)
}
}
public class CustTextFld: NSTextView {
func setContent(text: NSAttributedString, makeNotEditable: Bool) {
self.isEditable = true
self.selectAll(nil)
self.insertText(text, replacementRange: self.selectedRange())
self.isEditable = !makeNotEditable
}
// remove cursor
public override func mouseMoved(with event: NSEvent) {
}
public override func viewWillDraw() {
isHorizontallyResizable = true
isVerticallyResizable = true
isRichText = true
isSelectable = false
// isRichText = false
}
public override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
let path = NSBezierPath(rect: bounds)
NSColor.white.setStroke()
path.stroke()
}
}
extension NSAttributedString {
func height(containerWidth: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: containerWidth, height: CGFloat.greatestFiniteMagnitude),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
return ceil(rect.size.height)
}
func width(containerHeight: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: containerHeight),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
return ceil(rect.size.width)
}
}
这里的问题是我能够强制
AttributedText2
的大小,以确保它的宽度和高度正确:
NSAttributedString.height(containerWidth: )
我曾尝试获取内容大小但没有任何结果。我也尝试过做
textView.sizeToFit()
- 也没有结果。尝试使用几何阅读器来获取视图宽度 - 但它破坏了视图,并且视图的大小仍然不正确。
有人有什么想法吗?
如果我理解正确,那么我认为这可以解决问题。您所要做的就是将
AttributedText2
结构替换为以下内容:
public struct AttributedText2: View {
@Binding var text: AttributedString
var nsText: Binding<NSAttributedString> {
Binding(get: { NSAttributedString(text) }, set: { _ in })
}
public var body: some View {
GeometryReader { geometry in
AttributedTextInternal(attributedString: nsText)
.frame(width: geometry.size.width, height: nsText.wrappedValue.height(containerWidth: geometry.size.width))
}
}
}
请注意,它使用
GeometryReader
作为尺寸数据。集成后,它就变成了:
import Foundation
import SwiftUI
import Cocoa
@available(OSX 11.0, *)
public struct AttributedText2: View {
@Binding var text: AttributedString
var nsText: Binding<NSAttributedString> {
Binding(get: { NSAttributedString(text) }, set: { _ in })
}
public var body: some View {
GeometryReader { geometry in
AttributedTextInternal(attributedString: nsText)
.frame(width: geometry.size.width, height: nsText.wrappedValue.height(containerWidth: geometry.size.width))
}
}
}
@available(OSX 11.0, *)
public struct AttributedTextInternal: NSViewRepresentable {
@Binding var text: NSAttributedString
public init(attributedString: Binding<NSAttributedString>) {
_text = attributedString
}
public func makeNSView(context: Context) -> CustTextFld {
let textView = CustTextFld()
textView.setContent(text: text, makeNotEditable: true)
textView.backgroundColor = .clear
textView.layerContentsPlacement = .top
textView.layerContentsRedrawPolicy = .crossfade
return textView
}
public func updateNSView(_ textView: CustTextFld, context: Context) {
textView.setContent(text: text, makeNotEditable: true)
}
}
public class CustTextFld: NSTextView {
func setContent(text: NSAttributedString, makeNotEditable: Bool) {
self.isEditable = true
self.selectAll(nil)
self.insertText(text, replacementRange: self.selectedRange())
self.isEditable = !makeNotEditable
}
// remove cursor
public override func mouseMoved(with event: NSEvent) {
}
public override func viewWillDraw() {
isHorizontallyResizable = true
isVerticallyResizable = true
isRichText = true
isSelectable = false
// isRichText = false
}
public override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
let path = NSBezierPath(rect: bounds)
NSColor.white.setStroke()
path.stroke()
}
}
extension NSAttributedString {
func height(containerWidth: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: containerWidth, height: CGFloat.greatestFiniteMagnitude),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
return ceil(rect.size.height)
}
func width(containerHeight: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: containerHeight),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
return ceil(rect.size.width)
}
}
看起来像什么: