Ios 细分文本视图';将属性化字符串放入(可引用)节中

Ios 细分文本视图';将属性化字符串放入(可引用)节中,ios,uitextview,nstextview,nslayoutmanager,nstextstorage,Ios,Uitextview,Nstextview,Nslayoutmanager,Nstextstorage,我正在尝试实现一个非常简单的文本编辑器,它应该在macOS上与NSTextView一起工作,在iOS上与UITextView一起工作。此文本编辑器有一个工具栏按钮“分节符”,每次单击该按钮时,它都会在当前光标位置插入一个新的节。一节应为: 可视为一个节(通过在两个后续节之间添加可视分隔符,并可能添加一些垂直空白) 可参考。用户应该能够在编辑器中看到所有部分的列表,通过单击该列表中的项目,文本视图应该立即滚动到该部分的开头 在年,我问如何解决第一个问题,不幸的是,我还没有找到这方面的答案(尽管有一

我正在尝试实现一个非常简单的文本编辑器,它应该在macOS上与
NSTextView
一起工作,在iOS上与
UITextView
一起工作。此文本编辑器有一个工具栏按钮“分节符”,每次单击该按钮时,它都会在当前光标位置插入一个新的节。一节应为:

  • 可视为一个节(通过在两个后续节之间添加可视分隔符,并可能添加一些垂直空白)

  • 可参考。用户应该能够在编辑器中看到所有部分的列表,通过单击该列表中的项目,文本视图应该立即滚动到该部分的开头

  • 在年,我问如何解决第一个问题,不幸的是,我还没有找到这方面的答案(尽管有一个答案)

    然而,这个问题集中在第二个方面:
    如何在我的文本视图中维护所有部分的列表,其中每个部分都保留对相关文本的准确引用?

    这项任务的复杂性在于,用户可以随时复制和粘贴或简单地编辑文本的任何部分。因此,我不能保存一个简单的段落编号数组或类似的东西


    我所尝试的以及为什么这看起来是一项如此困难的任务:
  • 我的一个想法是将
    NSTextStorage
    子类化,并使用可变属性字符串数组作为其内部存储。然后,我将使用一个特殊的子类
    NSTextAttachment
    ,并将其用作文本存储中的分节符指示器。问题在于:

    第一个方法只传递没有任何属性的普通字符串,第二个方法只获取属性。这意味着在第一种方法中,我无法判断替换字符是否实际应该是分节符,因此我无法决定在内部文本存储数组中的何处创建新元素

    在第二种方法中,我不知道用户是否实际添加了新文本(在这种情况下,我必须在文本存储数组中为每个分节符属性添加一个新元素),或者用户是否只是更改了现有文本的某些属性(在这种情况下,新数组元素之前已经创建)

  • 我还考虑了在表视图或堆栈视图中使用多个文本视图的想法。但是,这不起作用,因为它会阻止用户在多个后续部分中选择(和删除)文本

  • 最后,我尝试了子类化
    NSLayoutManager
    ,但是关于它的文档非常少,似乎对我来说是个错误的地方。(毕竟,版面管理员的责任是文本的版面,而不是跟踪其结构。)


  • 有什么想法吗?我会玩NSRange的。它可能与您的方法无关,但可以用作建议

    指的是你的要点

    可视为节(通过在两个后续节之间添加可视分隔符,并可能添加一些垂直空白) 可参考。 用户应该能够在编辑器中看到所有部分的列表,通过单击该列表中的项目,文本视图应该立即滚动到该部分的开头

    UIButtons可以作为部分添加到textView中。按钮的宽度应为文本视图内的行宽度

    优点:

    • textView中的视图或按钮是可跟踪的,其y轴可以 如果文本粘贴在任何节中,则将更新
    • 选择该按钮后,可以调整textView的内容偏移量 可以将跟踪和节滚动到目标位置
    • 两个按钮之间的范围将为您提供相关文本的范围 内部部分。类似地,节的数组也是文本
    如何在文本视图中维护所有部分的列表,其中每个部分都保留对相关文本的准确引用

    首先确定一个部分是什么。直观地看,它似乎是一块连续的文本,其中几个文本串在一起形成一个完整的文档。但试着更深入一点:一个部分中的所有文本是否都具有相同的样式?相同的利润率?你真的需要跟踪分段吗,或者只跟踪分段休息也行吗

    接下来,由于您已经决定通过使用
    NSTextView
    UITextView
    来购买,并且由于您对这些类的需求超出了最常见的“包含一些可编辑文本的视图”用例,因此您需要进一步了解底层类是如何组合在一起的。主要的类是
    NSTextStorage
    NSTextContainer
    NSLayoutManager
    ,当然还有
    NSTextView
    (或者
    UITextView

    了解TextKit类是如何工作的,以及它们为您提供了哪些工具,将有助于您了解如何实现“部分”概念。以下是几个您可以选择的方法示例:

    • 构建自己的文本视图。文本视图所做的大部分工作实际上是由其他类完成的:文本容器、布局管理器和文本存储。您可以构建自己的视图,其中包含一系列文本容器,以便每个部分由不同的容器表示,每个容器都有自己的布局管理器和存储对象。这显然是最重要的工作,但它将提供对如何显示分区的大量控制。此外,如果您构建的视图可以在两种平台上工作,那么就不必担心
      UITextView
      NSTextView
      之间的差异

    • 让文本视图完成所有工作。我可以使用一个轻量级的小节实现
      func replaceCharacters(in range: NSRange, 
                             with str: String)
      
      func setAttributes(_ attrs: [NSAttributedString.Key : Any]?, 
                           range: NSRange)