每次属性字符串超过一定高度时都试图创建新的 NSTextView 吗?

Trying to create new NSTextView every time the attributed string exceeds a certain height?

每当属性字符串超过特定界限时,我都试图将新的 NSTextView 添加到我的集合视图中的最后一个索引。该代码在第 5 个项目之前完美运行,然后它开始在每次按下输入按钮时开始创建一个项目。我认为这是一个错误,但我不确定。如果有人能告诉我更好的方法或改进我现有的代码,我将不胜感激。下面是我的代码:

这是 CollectionViewItem

class DocumentItem: NSCollectionViewItem {

   var itemView: DocumentTextView?
   
   
   
   override func viewDidLoad() {
       super.viewDidLoad()
       self.itemView?.wantsLayer = true
       
       
   
       // Do view setup here.
   }

   override func loadView() {
       self.itemView = DocumentTextView(frame: NSZeroRect)
       self.view = self.itemView!
       
   }

   func getView() -> DocumentTextView {
       return self.itemView!
   }
   
   
   
}


这里是 collectionView 数据源

func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
            return DocList.count
        }
            
        
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
       
            let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue:  "DocumentItem"), for: indexPath)
            
            return item
}

这是 NSTextView 的子类

class DocumentTextView: NSTextView {
    
    
    var theContainer = NSTextContainer()
    var theStorage = NSTextStorage()
    var theManager = NSLayoutManager()
    
    
    var table = NSTextTable()
    var pdfPage: PDFPage?
    
    


   

    override init(frame frameRect: NSRect) {
        super.init(frame: NSRect(origin: frameRect.origin, size: NSSize(width: 800, height: 1131 )), textContainer: theContainer)
        theStorage.addLayoutManager(theManager)
        theManager.addTextContainer(theContainer)
        self.textContainerInset = CGSize(width: 50, height: 50)
        self.textContainer?.widthTracksTextView = true
        self.textContainer?.heightTracksTextView = true
        self.textContainer?.lineBreakMode = .byWordWrapping
        self.maxSize = NSSize(width: 800, height: 1131)
        self.backgroundColor = NSColor.fromHexString("ffffff")!
        self.isRichText = true
       

    
        
    }
  


   
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
        
    }
}

这是带来错误的函数


  func textDidChange(_ notification: Notification) {
        var textView = notification.object as? DocumentTextView
        let numberOfItems = theDocumentOutlineView.numberOfItems(inSection: 0)
        let theLastTextView = theDocumentOutlineView.item(at: numberOfItems - 1) as! DocumentItem
        if textView == theLastTextView.itemView {
            print(textView?.attributedString().size())
            if (textView?.attributedString().size().height)! >= 1106.0 {
                self.DocList.append(2)
                var set = Set<IndexPath>()
                set.insert(NSIndexPath(forItem: self.DocList.count - 1 , inSection: 0) as IndexPath)
                theDocumentOutlineView.insertItems(at: set)
                theDocumentOutlineView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
                var newFirstResponder = theDocumentOutlineView.item(at: self.DocList.count - 1) as! DocumentItem
                newFirstResponder.itemView?.delegate = self
                self.view.window?.makeFirstResponder(newFirstResponder.itemView)
                
            
            }
        }
    }

这是我的测试项目,也许它有帮助。文本视图的委托是它的视图控制器,NSCollectionViewItem。集合视图的视图控制器还接收 NSText.didChangeNotification 通知以检查文本的长度。 heightTracksTextView 的文本容器是 false

ViewController:

class ViewController: NSViewController, NSCollectionViewDataSource, NSCollectionViewDelegate {

    @IBOutlet weak var collectionView: NSCollectionView!
    var docList: [DocumentObject] = [DocumentObject(index: 0, string: NSAttributedString(string: "New 0"))]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.register(DocumentItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"))
        NotificationCenter.default.addObserver(self, selector: #selector(textDidChange),
            name: NSText.didChangeNotification, object: nil)
    }

    func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
        return docList.count
    }
            
    func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
        if let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"),
            for: indexPath) as? DocumentItem {
            item.representedObject = docList[indexPath.item]
            return item
        }
        return NSCollectionViewItem()
    }

    @objc func textDidChange(_ notification: Notification) {
        if let textView = notification.object as? NSTextView {
            if let theLastItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem,
                textView === theLastItem.itemView {
                //if textView.attributedString().size().height >= 1106.0 {
                print("\(textView.attributedString().size().height) \(textView.layoutManager!.usedRect(for: textView.textContainer!).size.height)")
                if let textContainer = textView.textContainer,
                    let heigth = textView.layoutManager?.usedRect(for: textContainer).size.height,
                    heigth >= 1106.0 {
                    DispatchQueue.main.async {
                        if let window = self.view.window,
                            window.makeFirstResponder(nil) { // end editing of previous item
                            self.docList.append(DocumentObject(index: self.docList.count - 1, string: NSAttributedString(string: "New \(self.docList.count)")))
                            let set: Set = [IndexPath(item: self.docList.count - 1, section: 0)]
                            self.collectionView.insertItems(at: set)
                            self.collectionView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
                            if let newItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem {
                                window.makeFirstResponder(newItem.itemView)
                            }
                        }
                    }
                }
            }
        }
    }

}

文档项:

class DocumentItem: NSCollectionViewItem, NSTextViewDelegate {

    var itemView: DocumentTextView?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
    }

    override func loadView() {
        self.itemView = DocumentTextView(frame: NSZeroRect)
        self.view = self.itemView!
        self.itemView?.delegate = self
    }
    
    override var representedObject: Any? {
        didSet {
            if let item = representedObject as? DocumentObject {
                itemView?.textStorage?.setAttributedString(item.string)
            }
        }
    }
    
    func textDidEndEditing(_ notification: Notification) {
        if let item = representedObject as? DocumentObject {
            item.string = itemView?.textStorage?.copy() as! NSAttributedString
        }
    }

}

文档对象:

class DocumentObject {

    var index: Int
    var string: NSAttributedString
    
    init(index: Int, string: NSAttributedString) {
        self.index = index
        self.string = string
    }

}