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(日)

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java:JWT的简单例子

【pom.xml】 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.3.12.RELEASE</version> </dependency> <dependency><groupId>org.springf…

程序猿成长之路之数据挖掘篇——决策树分类算法(1)——信息熵和信息增益

决策树不仅在人工智能领域发挥着他的作用&#xff0c;而且在数据挖掘中也在分类领域中独占鳌头。了解决策树的思想是学习数据挖掘中的分类算法的关键&#xff0c;也是学习分类算法的基础。 什么是决策树 用术语来说&#xff0c;决策树&#xff08;Decision Tree&#xff09;是…

STM32驱动-ads1112

汇总一系列AD/DA的驱动程序 ads1112.c #include "ads1112.h" #include "common.h"void AD5726_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE );//PORTA、D时钟使能 G…

SQLite数据库(数据库和链表双向转换)

文章目录 SQLite数据库一、SQLite简介1、SQLite和MySQL2、基于嵌入式的数据库 二、SQLite数据库安装三、SQLite的常用命令四、SQLite的编程操作1、SQLite数据库相关API&#xff08;1&#xff09;头文件&#xff08;2&#xff09;sqlite3_open()&#xff08;3&#xff09;sqlite…

Springboot拓展之整合邮件 JavaMail的使用与实操

邮件 电子邮件仍然是我们企业间交往的一种非常常见的方式 发送简单邮件 第一步首先导入坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId><version>2.6.13</version&…

架构师指南:现代 Datalake 参考架构

这篇文章的缩写版本于 2024 年 3 月 26 日出现在 The New Stack 上。 旨在最大化其数据资产的企业正在采用可扩展、灵活和统一的数据存储和分析方法。这一趋势是由企业架构师推动的&#xff0c;他们的任务是制定符合不断变化的业务需求的基础设施。现代数据湖体系结构通过将数…

设计模式——设计模式原则

设计模式 设计模式原则 单一职责原则&#xff08;SPS&#xff09;&#xff1a; 又称单一功能原则&#xff0c;面向对象五个基本原则&#xff08;SOLID&#xff09;之一 原则定义&#xff1a;一个类应该只有一个发生变化的原因 使用if else进行判断实现不好维护 模式场景&a…

ruoyi添加自己的菜单

先把自己自定义的view填写好 在菜单管理模块 因为我已经新增过&#xff0c;所以就看看我填的啥就行了 我发现一个问题&#xff0c;路由地址可以填index2或者scooldemo/index2都可以&#xff08;这个包含了文件夹路径&#xff09;&#xff0c;反正组件路径一定要填对就可以了。 …

刷代码随想录有感(112):动态规划——组合总和IV

题干&#xff1a; 代码&#xff1a; class Solution { public:int combinationSum4(vector<int>& nums, int target) {vector<int>dp(target 1, 0);dp[0] 1;for(int j 0; j < target; j){for(int i 0; i < nums.size(); i){if(j > nums[i] &…

CATIA_DELMIA_V5R2019安装包下载及安装教程破解

以下为V5-6R2019安装说明 1.将两卷安装文件解压到同一目录内&#xff0c;互相覆盖即可 &#xff08;按用户需要下载 CATIA 或者DELMIA&#xff09; 以上为 CATIA 的安装包 以上为 DELMIA 的安装包 两者合并到一起&#xff0c;同一目录 2.解压后运行setup.exe 如遇到报错&…

【代码随想录】【算法训练营】【第45天】 [198]打家劫舍 [213]打家劫舍II [337]打家劫舍III

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 45&#xff0c;周五&#xff0c;坚持不了一点~ 题目详情 [198] 打家劫舍 题目描述 198 打家劫舍 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 C语言 虚拟头…

Python | Leetcode Python题解之第165题比较版本号

题目&#xff1a; 题解&#xff1a; class Solution:def compareVersion(self, version1: str, version2: str) -> int:n, m len(version1), len(version2)i, j 0, 0while i < n or j < m:x 0while i < n and version1[i] ! .:x x * 10 ord(version1[i]) - o…

VBA技术资料MF164:列出文件夹中的所有文件和创建日期

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Gradle学习-1

1、APK构建流程 2、Gradle的安装 &#xff08;1&#xff09;安装Java JDK JAVA JDK 下载地址下载安装后需要配置环境变量gradle是运行在Java虚拟机上的&#xff0c;所以需要配置Java JDK &#xff08;2&#xff09;安装 Gradle Gradle下载官网下载安装后需要配置环境变量 …

「动态规划」如何求子数组中等差数列的个数?

413. 等差数列划分https://leetcode.cn/problems/arithmetic-slices/description/ 如果一个数列至少有三个元素&#xff0c;并且任意两个相邻元素之差相同&#xff0c;则称该数列为等差数列。例如&#xff0c;[1,3,5,7,9]、[7,7,7,7]和[3,-1,-5,-9]都是等差数列。给你一个整数…

通过开放解析智能分块提高 RAG 性能

如果要使用大型语言模型 &#xff08;&#xff09;LLMs 实现生成式 AI 解决方案&#xff0c;则应考虑使用检索增强生成 &#xff08;RAG&#xff09; 的策略来生成上下文感知提示LLM。在启用 LLM RAG 的预生产管道中发生的一个重要过程是删除文档文本&#xff0c;以便仅将文档中…

论文:R语言数据分析之机器学习论文

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 一、研究背景 全球范围内&#xff0c;乳腺癌是导致癌症发病率和死亡率的主要疾病之一。根据2018年…

BFS 解决最短路问题

例题一 解法&#xff08;bfs 求最短路&#xff09;&#xff1a; 算法思路&#xff1a; 利⽤层序遍历来解决迷宫问题&#xff0c;是最经典的做法。我们可以从起点开始层序遍历&#xff0c;并且在遍历的过程中记录当前遍历的层数。这样就能在找到出⼝的时候&#xff0c;得到起点…

会自动清除的文件——tempfile

原文链接&#xff1a;http://www.juzicode.com/python-tutorial-tempfile/ 在某些不需要持久保存文件的场景下&#xff0c;可以用tempfile模块生成临时文件或者文件夹&#xff0c;这些临时文件或者文件夹在使用完之后就会自动删除。 NamedTemporaryFile用来创建临时文件&…

教程:LVM操作讲解

LVM简介 在系统运维过程中&#xff0c;对磁盘扩缩容是常见的操作。如何高效的管理磁盘容量&#xff0c;lvm提供了很好的解决方案。 LVM将磁盘抽象成PV、VG、LV&#xff0c;方便用户进行磁盘管理&#xff0c;简单来讲&#xff0c;是由物理磁盘划分成PV&#xff0c;PV加入到具体…