我正在尝试实现一个非常简单的文本编辑器,它应该可以NSTextView
在 macOS 和UITextView
iOS 上使用。这个文本编辑器有一个工具栏按钮“ Section Break ”,每次点击它都会在当前光标位置插入一个新的部分。一个部分应该是:
在视觉上可识别为一个部分(通过在两个后续部分之间添加视觉分隔符并可能添加一些垂直空格),
可参考。用户应该能够在编辑器中看到所有部分的列表,并且通过单击该列表中的项目,文本视图应该立即滚动到该部分的开头。
在另一个问题中,我问如何解决第一个问题,不幸的是,我还没有找到关于这部分的答案(即使有一个仅适用于 macOS 的解决方案)。
然而,这个问题集中在第二个方面:
如何在我的文本视图中维护所有部分的列表,其中每个部分都保持对相关文本的准确引用?
此任务的复杂性在于用户可以随时复制和粘贴或简单地编辑文本的任何部分。因此,我不能保留一个简单的段落编号数组或类似的东西。
我尝试过的以及为什么这似乎是一项艰巨的任务:
我的一个想法是子类
NSTextStorage
化并使用一组可变属性字符串作为其内部存储。然后我会使用一个特殊的子类,NSTextAttachment
并将其用作我的文本存储中的分节指示符。问题在于文本视图仅在用户编辑文本时调用以下方法:func replaceCharacters(in range: NSRange, with str: String)
和
func setAttributes(_ attrs: [NSAttributedString.Key : Any]?, range: NSRange)
第一种方法只传递没有任何属性的纯字符串,第二种方法只获取属性。这意味着在第一种方法中,我无法判断替换字符是否实际上应该是分节符,因此我无法决定在我的内部文本存储数组中的哪个位置创建新元素。
在第二种方法中,我不知道用户是否实际添加了新文本(在这种情况下,我必须在我的文本存储数组中为每个分节符属性添加一个新元素),或者用户是否只是更改了现有的某些属性文本(在这种情况下,之前已经创建了新的数组元素)。
我还考虑过在表格视图或堆栈视图中使用多个文本视图的想法。但是,这不起作用,因为它会阻止用户在多个后续部分中选择(和删除)文本。
最后,我尝试了 subclassing
NSLayoutManager
,但是关于它的文档真的很薄,对我来说似乎是错误的地方。(毕竟布局管理器的职责是文本的布局,而不是跟踪它的结构。)