本文翻译整理自:Text System Storage Layer Overview(更新日期:2012-09-19
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextStorageLayer/TextStorageLayer.html#//apple_ref/doc/uid/10000087i
文章目录
- 一、文本系统存储层简介概述
- 1、谁应该阅读此文档
- 2、本文件的组织
- 3、另见
- 二、存储层:NSTextStorage类
- 三、布局几何:NSTextContainer类
- 四、创建文本存储
- 五、更改文本存储
- 六、显示文本容器
- 七、计算区域、边界矩形和插图
- 八、跟踪文本视图的大小
- 九、创建NSTextStorage的子类
一、文本系统存储层简介概述
文本系统存储层概述讨论了Cocoa文本系统用于存储用于文本布局的文本和几何图形信息的工具。
1、谁应该阅读此文档
如果您需要直接使用文本存储层,您应该阅读本文档。
例如,您可能需要以编程方式更改文本存储对象中的文本或扩展其功能。
要理解本材料,您应该对Cocoa编程约定有一个大致的了解。
您还应该阅读文本系统概述。
2、本文件的组织
本文档包含以下文章:
- 存储层:NSTextStorage类提供了文本存储对象功能的一般介绍。
- 布局几何:NSTextContainer类解释了文本容器如何定义系统布局文本的区域以及它们如何与其他文本系统对象交互。
- 创建文本存储说明如何创建和设置文本存储对象。
- 更改文本存储描述了以编程方式编辑文本存储对象中的文本的过程。
- 显示文本容器说明了如何在文本视图或其他NSView对象中显示文本存储对象中的文本。
- 计算区域、边界矩形和插图讨论了如何定义文本容器的文本布局区域。
- 跟踪文本视图的大小说明了如何设置文本容器,以便其几何形状与其关联的文本视图交互。
- 创建NSTextStorage的子类讨论了NSTextStorage子类的要求。
3、另见
如需进一步阅读,请参阅以下文件:
- 属性字符串编程指南 提供了有关构建
NSTextStorage
的属性字符串对象的信息。
NSTextStorage
是NSMutableAttributedString
的子类。 - 文本布局编程指南 描述了涉及文本存储、文本容器、文本视图和布局管理器对象的布局过程。
二、存储层:NSTextStorage类
一个NSTextStorage
对象 用作Cocoa文本系统的字符数据存储库。
该数据的格式是一个属性字符串,它是一个字符序列(在Unicode编码中)和应用于它们的属性(如字体、颜色和段落样式)。
表示属性字符串的类是NSAttributedString
和NSMutableAttributedString
,其中NSTextStorage
是一个子类。
从概念上讲,文本块中的每个字符都有一个与之关联的键和值的字典。
键命名一个属性(如NSFontAttributeName
),关联值指定该属性的特征(如Helvetica 12-point
)。
有关属性字符串的更多信息,请参阅 属性字符串编程指南 。
图1说明了NSTextStorage
类,显示了它的NSMutableAttributedString
组件和附加功能。
图1 NSTextStorage的功能
通过NSTextStorage
方法,您可以通过编程方式对NSTextView
对象显示的文本的属性进行操作;例如,您的代码可以遍历文本,收紧或放宽特定字体和大小的所有字符的字距。
NSTextView
对象使用户能够通过直接操作来影响字符属性;例如,用户选择一些文本,并通过选择Tighten菜单命令来减少字符之间的行间距。
三、布局几何:NSTextContainer类
一个NSTextContainer
对象定义了Cocoa文本系统在页面上布置文本的区域。
默认情况下,文本容器定义一个简单的矩形区域,但是您可以创建子类来定义任何几何形状的区域,包括文本流动周围有孔的区域。
NSTextContainer
中提供了四个主要文本对象之一。
文本容器与文本存储对象、布局管理器和文本视图一起工作,以存储、布局和显示属性化的文本字符串。
特别是,文本容器直接与布局管理器一起工作,布局管理器使用一个NSTypesetter
对象来生成线片段矩形,在其中放置字形(字符形状),如线片段生成
当排字器生成行片段时,文本容器特别关注文本布局的前进方向。
布局方向有两个方面:行扫描和行移动。
行扫描是系统在行内布置字形的方向。
行移动是系统在页面上布置行的方向。
排字器对象确定这些参数,并将它们作为常量值传递给文本容器。
行扫描和行移动都可以从左到右、从右到左、从上到下和从下到上进行。
此外,排字器可以指定不移动行。
注意:内置排字器目前仅支持从上到下的行移动和从左到右的扫描。
这些排字器确实通过在行片段内以适当的显示顺序排列来处理双向文本(希伯来语和阿拉伯语),但它们不使用行扫描机制。
布局管理器维护一个文本容器数组。
它向它的委托发送一条消息,每当它填充一个文本容器时,委托就可以添加一个新的要填充的文本容器。
如果文本容器改变了大小,或者如果对容器中布局文本的更改使布局无效,那么系统将使布局管理器数组中所有后续容器中的布局无效。
您可以指定文本容器跟踪其文本视图的大小;也就是说,如果用户调整视图大小,文本容器将调整自身大小以匹配。
有关详细信息,请参阅跟踪文本视图的大小。
NSTextContainer
实例具有初始化、管理与布局管理器和文本视图的连接、获取和设置容器大小、生成行片段和命中测试的方法。
此外,NSTextContainer
具有获取和设置应用于行片段的填充量的方法。
行片段填充是行片段末尾包含的额外空间,因此布局的字形不会直接接触页面上的其他元素,例如图形。
四、创建文本存储
作为一个类集群的抽象类,分配和初始化一个NSTextStorage
对象实际上会产生一个私有子类的实例,可以使用任何NSAttributedString
或NSMutableAttributedString
初始化方法来创建一个NSTextStorage
对象。
创建文本存储对象后,使用addLayoutManager:
将NSLayoutManager
对象添加到文本存储中。
单个文本存储对象可以有多个布局管理器(这就是为什么此方法名称以“add”而不是“set”开头)。
以这种方式创建文本存储对象并添加布局管理器是以编程方式组装文本系统过程的一部分,在 Cocoa文本体系结构指南 中的“创建文本系统对象”中有更详细的描述。
您还可以创建一个NSTextView
对象并让它自动组装文本系统,在这种情况下文本视图创建(并稍后释放)文本存储对象。
有关详细信息,请参阅以编程方式创建NSTextView。
五、更改文本存储
一个NSTextStorage
对象的行为最好的说明是按照您发送的消息来更改它的文本。
有三个阶段来编辑一个文本存储对象:
- 第一阶段是向它发送一个
beginEditing
消息来宣布一组更改。 - 在第二阶段,您向它发送一些编辑消息,例如
deleteCharactersInRange:
和addAttributes:range:
,以影响字符或属性的更改。
每次发送此类消息时,文本存储对象都会调用edited:range:changeInLength:
以跟踪自收到beginEditing
消息以来受影响的字符范围。 - 对于第三阶段,当您完成对文本存储对象的更改后,您将向它发送
endEditing
消息。
这将导致它调用自己的processEditing
方法,在记录的更改字符范围内固定属性。
(有关属性固定的信息,请参阅 文本属性编程主题 )。
修复属性后,文本存储对象向每个关联的布局管理器发送一条消息,指示文本存储对象中已更改的范围以及这些更改的性质。
布局管理器反过来使用此信息重新计算其字形位置,并在必要时重新显示。
NSTextStorage
还保留一个委托,并在处理编辑前后向其发送消息。
六、显示文本容器
您通常使用NSTextView
对象来显示NSTextContainer
中的文本。
一个NSTextView
只能有一个NSTextContainer
;但是,因为这两个是独立的对象,您可以替换一个NSTextView
的容器来更改它显示的文本的布局。
您还可以在任何NSView
中显示NSTextContainer
的文本,方法是用lockFocus
锁定图形焦点并使用NSLayoutManager
方法drawBackgroundForGlyphRange:atPoint:
和drawGlyphsForGlyphRange:atPoint:
。
如果您不需要实际显示文本——例如,如果您只计算换行符或行数或页数——您可以使用NSTextContainer
而不需要NSTextView
。
七、计算区域、边界矩形和插图
一个NSTextContainer
对象的区域是由一个边界矩形定义的其坐标系从左上角的(0,0)开始。
这个矩形的大小由containerSize
方法返回,并使用setContainerSize:
.您可以定义一个容器的区域,使其始终保持相同的形状,例如直径是边界矩形尺寸较窄的圆,或者您可以定义相对于边界矩形的区域,例如适合边界矩形内部的椭圆形区域(当边界矩形为正方形时,这是一个圆)。
无论文本容器的形状如何,它的NSTextView
总是剪辑绘制到其边界矩形。
图1说明了文本容器的这些方面。
图1 文本容器区域、边框和插图
一个NSTextContainer
的子类通过覆盖三个方法来定义其区域。
第一个方法,isSimpleRectangularTextContainer
,指示该区域当前是否为非旋转矩形,从而允许NSLayoutManager
优化文本布局(由于自定义文本容器通常定义更复杂的区域,因此您对该方法的实现可能会返回NO
)。
第二种方法,containsPoint:
,用于测试鼠标事件,并确定给定点是否位于该区域中。
第三种方法,lineFragmentRectForProposedRect:sweepDirection:movementDirection:remainingRect:
,用于文本的实际布局,根据可用于放置文本的矩形定义区域。
此过程在线段生成
一个文本容器通常覆盖它的文本视图,但是它可以用setTextContainerInset:
方法插入到视图框架中。
文本容器的边框从插入位置开始,然后建立文本容器区域的限制。
当文本容器跟踪其文本视图的高度或宽度时,插图还有助于确定边框的大小,如跟踪文本视图的大小中所述。
请注意,文本容器插页不能完全确定容器在文本视图中的位置。
文本视图计算文本容器在其中的位置,它试图保持文本容器插页给出的空间量,但是根据文本视图和文本容器的相对大小,这可能是不可能的。
还有可能分配的空间比文本容器插页指定的空间多。
如果您想确定文本容器的真实位置——例如,在容器和视图坐标之间进行转换——您应该使用textContainerOrigin
方法,这是文本视图计算的实际值。
八、跟踪文本视图的大小
您可以设置NSTextContainer
对象来跟踪其NSTextView
对象的大小,并在文本视图大小更改时调整其自身的大小以匹配。
setHeightTracksTextView:
和setWidthTracksTextView:
方法允许您控制任一维度的跟踪。
当文本容器调整其大小以匹配其文本视图时,它会考虑文本视图指定的插页,因此边界矩形会尽可能从每条边插入。
换句话说,跟踪其文本视图大小的文本容器总是比给定维度中的文本视图小两倍。
假设文本容器设置为跟踪宽度,其文本视图为其插页(10,10)。
现在,如果文本视图的宽度更改为138,则文本容器的左上角设置为位于(10,10),其宽度设置为118,因此其右边缘距文本视图右边缘10点。
它的高度保持不变。
无论是否跟踪其文本视图的大小,文本容器都不会随着文本的添加或删除而增长或缩小;相反,NSLayoutManager
对象根据文本容器中实际填充文本的部分调整文本视图的大小。
要允许以这种方式调整文本视图的大小,请根据需要使用setVerticallyResizable:
或setHorizontallyResizable:
方法(继承自NSText
),将文本容器设置为不跟踪其文本视图的大小,并将文本容器的大小设置为足够大的尺寸,以容纳大量文本——例如,10,000,000点(这在处理或存储方面不会产生任何成本)。
请注意,文本视图可以根据其文本容器调整大小,文本容器可以根据其文本视图调整自身大小。
如果您将两个对象设置为在同一维度上自动调整大小,您的应用程序可能会陷入无限循环。
当文本添加到文本容器时,文本视图会调整大小以适应实际用于文本的区域;这会导致文本容器自行调整大小并中继其文本,这会导致文本视图再次调整大小,依此类推。
每种类型的大小跟踪都有其适当的用途;确保在任一维度上只使用一个。
九、创建NSTextStorage的子类
NSTextStorage
不是一个完全具体的类;相反,它是一个类集群的抽象超类。
它定义了NSLayoutManager
对象的存储并实现了一些方法,但不向子类提供原始的属性字符串方法。
子类必须定义其属性字符串的存储,通常是NSMutableAttributedString
类型的实例变量,覆盖init
并定义自己的初始化方法,并实现NSAttributedString
和NSMutableAttributedString
的原始方法是:
string
attributesAtIndex:effectiveRange:
replaceCharactersInRange:withString:
setAttributes:range:
除了这些要求之外,如果子类覆盖或添加任何直接更改其字符或属性的方法,这些方法必须在执行更改后调用edited:range:changeInLength:
以使更改跟踪信息保持最新。
有关详细信息,请参阅方法描述。
2024-06-16(日)
把想做的做了,以后就没有那么多留恋了