NSTextView 拖动带有自定义属性的文本

NSTextView drag text with custom attributes

我的 NSTextView 子类有问题。我的视图包含带有自定义属性的属性字符串,因此我必须实现以下粘贴板方法以确保将我的自定义属性复制到粘贴板上。

writeSelection(to:type:)
readSelection(from:type:)

在 readSelection 中,我手动读取粘贴板上的字符串,并将其写入 rangeForUserTextChange 的 NSTextView 的 textStorage。

override func readSelection(from pboard: NSPasteboard, type: String) -> Bool {


    // Manually reads the text on the pasteboard, and write it to textStorage

    if type == astroBoardAttributedString {

        if let string = pboard.string(forType: astroBoardAttributedString) {

            let attrString = NSAttributedString(string: string)

            self.textStorage?.replaceCharacters(in: self.rangeForUserTextChange, with: attrString)


            return true

        }


    }

    return super.readSelection(from: pboard, type: type)

}

现在的问题是,当我 select 并将文本从第 5 行向上拖动到第 1 行下方时,文本会正确插入第 1 行下方,但是系统随后会尝试从第 1 行中删除文本5 曾经是,现在包含第 4 行,因为在第 1 行下面添加了额外的一行。

/*
line 1 <-- Drop after this line
line 2
line 3
line 4
line 5 <-- Drag from this line

The expected outcome is 

line 1
line 5
line 2
line 3
line 4

The actual resulting outcome is 

line 1
line 5
line 2
line 3
line 5

What happens is

line 1
line 5  <-- Line inserted here (correct)
line 2
line 3
line 4 <-- This line is removed instead :(
line 5 <-- This is the line that should be removed.
*/

如您所见,系统正在删除更改长度后的行。当拖放方法删除从文本视图中拖动的 textStorage 中的文本时,我找不到任何用于拦截的委托方法。

联系Apple寻求支持后,我得到了答案,这里是引用。

The code snippet you provided shows that when you read from the pasteboard and change the text storage, you don’t notifiy the other components by calling shouldChangeText(...) and didChangeText(), which causes an inconsistency between the text storage and rendering. You should be able to fix the issue by wrapping the code like below:

self.shouldChangeText(in:self.rangeForUserTextChange, replacementString: string)
self.textStorage?.replaceCharacters(in: self.rangeForUserTextChange, with: string)
self.didChangeText()