Apple - Text System Storage Layer Overview

本文翻译整理自: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的属性字符串对象的信息。
    NSTextStorageNSMutableAttributedString的子类。
  • 文本布局编程指南 描述了涉及文本存储、文本容器、文本视图和布局管理器对象的布局过程。

二、存储层:NSTextStorage类

一个NSTextStorage对象 用作Cocoa文本系统的字符数据存储库。
该数据的格式是一个属性字符串,它是一个字符序列(在Unicode编码中)和应用于它们的属性(如字体、颜色和段落样式)。
表示属性字符串的类是NSAttributedStringNSMutableAttributedString,其中NSTextStorage是一个子类。
从概念上讲,文本块中的每个字符都有一个与之关联的键和值的字典。
键命名一个属性(如NSFontAttributeName),关联值指定该属性的特征(如Helvetica 12-point)。
有关属性字符串的更多信息,请参阅 属性字符串编程指南
图1说明了NSTextStorage类,显示了它的NSMutableAttributedString组件和附加功能。

图1 NSTextStorage的功能
在这里插入图片描述


通过NSTextStorage方法,您可以通过编程方式对NSTextView对象显示的文本的属性进行操作;例如,您的代码可以遍历文本,收紧或放宽特定字体和大小的所有字符的字距。
NSTextView对象使用户能够通过直接操作来影响字符属性;例如,用户选择一些文本,并通过选择Tighten菜单命令来减少字符之间的行间距。


三、布局几何:NSTextContainer类

一个NSTextContainer对象定义了Cocoa文本系统在页面上布置文本的区域。
默认情况下,文本容器定义一个简单的矩形区域,但是您可以创建子类来定义任何几何形状的区域,包括文本流动周围有孔的区域。

NSTextContainer中提供了四个主要文本对象之一。
文本容器与文本存储对象、布局管理器和文本视图一起工作,以存储、布局和显示属性化的文本字符串。
特别是,文本容器直接与布局管理器一起工作,布局管理器使用一个NSTypesetter对象来生成线片段矩形,在其中放置字形(字符形状),如线片段生成

当排字器生成行片段时,文本容器特别关注文本布局的前进方向。
布局方向有两个方面:行扫描和行移动。
行扫描是系统在行内布置字形的方向。
行移动是系统在页面上布置行的方向。
排字器对象确定这些参数,并将它们作为常量值传递给文本容器。
行扫描和行移动都可以从左到右、从右到左、从上到下和从下到上进行。
此外,排字器可以指定不移动行。

注意:内置排字器目前仅支持从上到下的行移动和从左到右的扫描。
这些排字器确实通过在行片段内以适当的显示顺序排列来处理双向文本(希伯来语和阿拉伯语),但它们不使用行扫描机制。

布局管理器维护一个文本容器数组。
它向它的委托发送一条消息,每当它填充一个文本容器时,委托就可以添加一个新的要填充的文本容器。
如果文本容器改变了大小,或者如果对容器中布局文本的更改使布局无效,那么系统将使布局管理器数组中所有后续容器中的布局无效。

您可以指定文本容器跟踪其文本视图的大小;也就是说,如果用户调整视图大小,文本容器将调整自身大小以匹配。
有关详细信息,请参阅跟踪文本视图的大小。

NSTextContainer实例具有初始化、管理与布局管理器和文本视图的连接、获取和设置容器大小、生成行片段和命中测试的方法。
此外,NSTextContainer具有获取和设置应用于行片段的填充量的方法。
行片段填充是行片段末尾包含的额外空间,因此布局的字形不会直接接触页面上的其他元素,例如图形。


四、创建文本存储

作为一个类集群的抽象类,分配和初始化一个NSTextStorage对象实际上会产生一个私有子类的实例,可以使用任何NSAttributedStringNSMutableAttributedString初始化方法来创建一个NSTextStorage对象。

创建文本存储对象后,使用addLayoutManager:NSLayoutManager对象添加到文本存储中。
单个文本存储对象可以有多个布局管理器(这就是为什么此方法名称以“add”而不是“set”开头)。

以这种方式创建文本存储对象并添加布局管理器是以编程方式组装文本系统过程的一部分,在 Cocoa文本体系结构指南 中的“创建文本系统对象”中有更详细的描述。
您还可以创建一个NSTextView对象并让它自动组装文本系统,在这种情况下文本视图创建(并稍后释放)文本存储对象。
有关详细信息,请参阅以编程方式创建NSTextView。


五、更改文本存储

一个NSTextStorage对象的行为最好的说明是按照您发送的消息来更改它的文本。
有三个阶段来编辑一个文本存储对象:

  1. 第一阶段是向它发送一个beginEditing消息来宣布一组更改。
  2. 在第二阶段,您向它发送一些编辑消息,例如deleteCharactersInRange:addAttributes:range:,以影响字符或属性的更改。
    每次发送此类消息时,文本存储对象都会调用edited:range:changeInLength:以跟踪自收到beginEditing消息以来受影响的字符范围。
  3. 对于第三阶段,当您完成对文本存储对象的更改后,您将向它发送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并定义自己的初始化方法,并实现NSAttributedStringNSMutableAttributedString的原始方法是:

  • string
  • attributesAtIndex:effectiveRange:
  • replaceCharactersInRange:withString:
  • setAttributes:range:

除了这些要求之外,如果子类覆盖或添加任何直接更改其字符或属性的方法,这些方法必须在执行更改后调用edited:range:changeInLength:以使更改跟踪信息保持最新。
有关详细信息,请参阅方法描述。


2024-06-16(日)

把想做的做了,以后就没有那么多留恋了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/857618.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WebSocket走私实践(附赠LiveGBS监控系统未授权管理员密码重置)

WebSocket走私实践(附赠LiveGBS监控系统未授权管理员密码重置) 对此,我特别感谢TryHackMe和HackTheBox academy,永远相信和追随英国TryHackMe所教导的网络安全知识,并保持学习 WebSocket走私相关的知识在这里 前段时间学习过htt…

小程序 UI 设计缔造独特魅力

小程序 UI 设计缔造独特魅力

[信号与系统]有关时域信号与频域信号的转换

为什么时域信号通过傅里叶变换就可以变成频域信号 时域信号通过傅里叶变换变成频域信号的原因在于傅里叶变换的数学原理和信号的性质。傅里叶变换提供了一种将信号从时域表示转换为频域表示的方法,揭示了信号的频率成分。这一转换的基础在于以下几个关键概念&#…

uniapp 底部菜单栏书写

{"pages": [{"path": "pages/index/index","style": {"navigationBarTitleText": "首页"}},{"path": "pages/my/my","style": {"navigationBarTitleText": "我的&q…

vue3中的$attrs

作用是可以看到父组件给子组件传过的内容&#xff0c;子组件没有使用 父组件 <template><div class"father"><h3>父组件</h3><Child :a"a" :b"b" :c"c" :d"d" :aaa"aaa" v-bind&quo…

qt 简单实验 一个可以向右侧拖拽缩放的矩形

1.概要 目的是设置一个可以拖拽缩放的矩形&#xff0c;这里仅用右侧的一个边模拟这个过程。就是为了抓住核心&#xff0c;这个便解决了&#xff0c;其他的边也是一样的。而这个更能体现原理。 2.代码 2.1 resizablerectangle.h #ifndef RESIZABLERECTANGLE_H #define RESIZ…

Redis源码学习:跳表(Skip List)的工作原理详解

什么是跳表 跳表&#xff08;Skip List&#xff09;&#xff0c;首先它是链表&#xff0c;是一种随机化的数据结构&#xff0c;Redis 使用跳表作为有序集合&#xff08;Sorted Set&#xff09;的底层实现之一。跳表能够提供高效的插入、删除、查找操作。本文通过阅读源码来分析…

python对象转字典对象及序列化

python对象转字典 1、为什么要对python对象转换为字典 python字典与json对象结构相似&#xff0c;json数据结构是最常用的数据结构 2、python对象转字典及序列化的核心点在哪 python对象有很多内置属性并不是我们所需要的python字典对象在序列化的时候&#xff0c;时间字段…

grafana 通过自定义API获取数据

一、安装插件 安装infinity插件 二、配置数据源 三、配置图表 1、数据 这边提供一个go的demo package mainimport ("math/rand""net/http""time""github.com/gin-gonic/gin" )func main() {router : gin.Default()rand.Seed(time.…

【SQL】UNION 与 UNION ALL 的区别

在 SQL 中&#xff0c;UNION 和 UNION ALL 都用于将两个或多个结果集合并为一个结果集&#xff0c;但它们在处理重复数据方面有显著区别。以下是它们的详细区别&#xff1a; 1. UNION UNION 操作符用于合并两个或多个 SELECT 语句的结果集&#xff0c;并自动去除结果集中重复…

c# 学习笔记 PropertyChangedEventHandler、 =>、DependencyObject、DataContext

在C#中&#xff0c;PropertyChangedEventHandler 和 PropertyChanged 常常与 INotifyPropertyChanged 接口一起使用&#xff0c;这是实现数据绑定和通知机制的关键部分&#xff0c;尤其在WPF (Windows Presentation Foundation) 或其他支持数据绑定的UI框架中。 PropertyChang…

怎样去掉卷子上的答案并打印

当面对试卷答案的问题时&#xff0c;一个高效而简单的方法是利用图片编辑软件中的“消除笔”功能。这种方法要求我们首先将试卷拍摄成照片&#xff0c;然后利用该功能轻松擦除答案。尽管这一方法可能需要些许时间和耐心&#xff0c;但它确实为我们提供了一个可行的解决途径。 然…

【2024.6.22】今日科技时事:科技前沿大事件

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

如何避免vue的url中使用hash符号?

目录 1. 安装 Vue Router 2. 配置 Vue Router 使用 history 模式 3. 更新 main.js 4. 配置服务器以支持 history 模式&#xff08;此处需要仔细测试&#xff09; a. Nginx 配置 b. Apache 配置 5. 部署并测试 总结 在 Vue.js 项目中&#xff0c;避免 URL 中出现 # 符号的…

docker-compose功能、操作

文章目录 前言主要功能基本用法 前言 docker-compose 是一个用于定义和运行多容器 Docker 应用的工具。它使用一个 YAML 文件&#xff08;通常命名为 docker-compose.yml&#xff09;来配置应用的服务、网络和卷等属性。通过 docker-compose&#xff0c;你可以利用一个单一的命…

YAML 入门教程

YAML 是 "YAML Aint a Markup Language"&#xff08;YAML 不是一种标记语言&#xff09;的递归缩写&#xff0c;是一种人类可读的完整的数据序列化语言。YAML 的意思其实是&#xff1a;"Yet Another Markup Language"&#xff08;仍是一种标记语言&#xf…

宝塔部署GeoServer教程

前期准备&#xff1a;下载geoserver 直接用我上传的geoserver或者是去官网下https://geoserver.org/release/stable/ 压缩包的geoserver版本是&#xff1a;2.25.1 jdk要求版本是&#xff1a;jdk11以上 tomcat版本&#xff1a;可选8或者9&#xff0c;建议用9 windows选择Window…

linux./xxx.py :Command not found

从windows传入linux系统中的py文件&#xff0c;在运行时出现了如标题所示的错误 第一行#!/bin/python3 但是却无法使用./xxx.py运行&#xff0c;通过一番调试&#xff0c;发现 windows的换行符与linux的换行符不一致导致了错误的发生 如何解决这个问题&#xff0c;使用dos2unix…

视频监控统一管理平台LntonCVS安防视频监控系统视频汇聚方案

LntonCVS平台最初被设计为一个以视频汇聚为核心的平台。那么&#xff0c;什么是视频汇聚平台&#xff0c;以及它是如何处理视频资源的呢&#xff1f;简单来说&#xff0c;视频汇聚平台能够从不同的视频源&#xff08;如直播和点播&#xff09;收集、整合和展示视频内容。以下是…

春天,快速恢复能量的10件小事(不妨试试)

春天快速恢复能量的十件小事&#xff0c;不妨试试随着天气回暖&#xff0c;万物都在恢复生机。 只是很多朋友感慨自己似乎总有些能量不足&#xff0c;没干什么重活累活&#xff0c;但觉得浑身疲乏&#xff0c;精神状态很低迷&#xff0c;不仅容易走神&#xff0c;而且记忆力也在…