Session:https://developer.apple.com/videos/play/wwdc2021/10061/
通过本文你将会了解到 TextKit 1 到 TextKit 2 的变化内容,并且可以深入了解 TextKit 2 的内部的工作原理和机制。
TextKit 是 Apple 在 iOS 7 中推出的文本处理工具包。用于驱动处理文本的计算、布局、渲染等文本相关的核心功能,它通过很少的几个类帮助开发者完成在之前必须使用 CoreText 通过复杂计算才能完成的任务,提高了 iOS 开发者对于文字展示和交互的开发效率,实际上它也是基于 CoreText 封装的高层次 API。然而在早在 20 多年前,TextKit 就已经首次出现在 OpenStep 的系统上。多年来,它从 macOS 10 就开始与我们一起成长和发展。从 iOS 第一个版本到 iOS 7 以及今天的 macOS 11 和 iOS 14,TextKit 在底层默默地为所有 Apple 的设备提供了最基本的文本功能服务着。
以上介绍的 TextKit 我们可以称之为 TextKit 1,几十年以来,设计和技术工程原理发生了很大变化,TextKit 1 最原始的设计原则,也已经有些过时了,因此提供与新技术完美集成的同时仍能提供高标准高性能的 API 变得更具挑战性。这也是为什么推出下一代 TextKit 的原因,TextKit 2 是 Apple 的下一代文本引擎,建立在一系列前瞻性设计原则之上。让我们一起来了解一下吧。
其实在 MacOS Big Sur 中,Apple 更新了操作系统中很多文本组件底层实现,在幕后已经使用了 TextKit 2。老生常谈,让我们来先看下 TextKit 2 的架构:
TextKit 1 和 TextKit 2 在系统中是共同存在的。就像它的前身一样,TextKit 2 建立在 Foundation、Quartz 和 Core Text 之上。UIKit 和 AppKit 中的文本控件建立在 TextKit 2 之上。
当然 TextKit 2 还保留了其前身的 MVC 设计。Model 和 Controller 是我们这次最大的变化部分,其中增加很多的新的朋友,当然也不要害怕,我们后文中会一一介绍。
那么先让我们从设计原则开始逐步深入我们今天的内容。TextKit 2 的核心设计原则是
所有三个原则都很重要,这是构建 TextKit 2 的最核心的思想,Apple 希望可以尽可能的去完美的实现这些特性,然而,现实中也做一些平衡。首先我会简单的介绍下各个核心原则的内容,以便让你对今天的内容有一个初步的概念:
没错,这个就是我们今天介绍的核心内容,接下去,让我们一个个来深入了解。
首先我们将会从准确性开始介绍,在准确性方面,Apple 抽象了字形处理,为国际文本提供一致的体验。Apple 设备在被世界各地的用户使用着,因此为所有语言的文本提供正确的布局、渲染和交互是非常重要的。我们希望每个人都能够在他们的设备上阅读文本并与之交互。然而在 TextKit 1 的一些 API 的设计使得很难以正确的方式处理国际化文本。
在开始本章节之前,我们可以先了解下排版系统中关于文本显示部分的重要概念,也可以对排版系统做一个基本的入门。
排版系统中文本显示的一个重要的过程就是字符到字形的转换。
字符(Characters):字符是信息本身的元素,而字形是字符的图形表征,字符还会有其它表征比如发音。字符在计算机中其实就是一个编码,某个字符集中的编码,比如 Unicode 字符集,就囊括了大都数存在的字符。
字形(Glyphs):字形是图形,一般都存储在字体文件中,字形也有它的编码,也就是它在字体中的索引。一个字符可以对应多个字形(不同的字体,或者同种字体的不同样式:粗体斜体等)多个字符也可能对应一个字形。
许多西方语言中,一个字形 Glyphs 通常代表一个字符。
但这并不总是正确的。你可以有多个字形代表一个字符,也可以相反。一个字形可以代表多个字符。这种用于表示多个字符的单个字形称为连字。
在西方语言中没有太多的连字,它们通常不会影响文本的易读性。你可以在没有连字的情况下阅读它。但并非所有语言都如此。像阿拉伯语和梵文这样的语言使用了很多连字,连字则会影响可读性。如阿拉伯文字的这个词。这是一个乌尔都语单词,意思是"时刻"。右侧用连字绘制的完整单词与左侧的单个字符看起来非常不同。
在 TextKit 1 中的许多 API 需要使用字形索引或范围。例如要获取某些文本的边界矩形,你需要知道你想要的文本的字形范围,在西方语言中,索引的获取是相对容易且正确的,然而在连字的情况下,获取正确的索引则不是一个简单的事情。
由于许多 TextKit 1 API 需要字形范围,因此使用这些 API 可能会破坏复杂语言的布局和渲染的准确性。这就是 TextKit 2 抽象字形处理的原因。TextKit 2 使用 CoreText 渲染所有文本,在 TextKit 2 中,你不需要管理复杂字形。相反,你可以使用更高级别的抽象对象来控制文本布局和交互。
阅读参考资料:https://devma.cn/blog/2016/04/14/ios-coretextru-men-zhi-zi-xing/
https://juejin.cn/post/6844903838252531725
它包含文本选择的所有必要上下文信息,例如其词语粒度、上下文关联性以及构成选择的文本范围。NSTextSelection
上的这些属性都是只读的,因此你不会修改选择对象的实例从而错误的更改它们。
如果需要改变选择的文本的信息,那么可以直接使用 NSTextSelectionNavigation
对象来查询和更新选择的文本范围。
它们与 UIKit 中的 UITextPosition 和 UITextRange 类非常相似,只是你不在需要对它们进行子类化。大多数情况下,你可以在 TextKit 2 中使用默认位置和范围对象。使用对象而不是数字而是更具表现力的文档模型,因为范围是根据彼此相对的位置定义的。如下的 HTML 文档对象模型就是一个很好的例子。
这就是 TextKit 2 中对准确性所做的一些改变。
接下来是安全性方面的介绍。在这方面,TextKit 2 更加强调值语义,以更好地与 Swift 和 SwiftUI 等技术的保持一致。什么是值语义呢?值类型保留数据的唯一副本,以防止该数据发生变更,这可以避免意外共享相关内存从而引发未感知的变化,从而让我们的代码更安全、更稳定。但是值类型并不是实现此效果的唯一方式。不可变类也具有初始化后无法更改的特性,这也可以防止了其数据的变化。这些类的行为类似于值类型,因此我们将它们称为具有值语义。
在 TextKit 2 中的许多类都是以这种方式设计的。为了说明这种设计的优势,让我们重新梳理一下 TextKit 1 渲染流程:
简短的说明:文字更新导致文本存储的变化并且通知布局管理器,然后布局管理器将生成字形、定位它们并将它们直接绘制到视图中。使用这种方式直接绘制到视图中的方式,很难弄清楚在何处分隔文本以创建自定义绘制空间。
让我们在来看下 TextKit 2 的渲染流程:
新的流程则会是:
文本的更新通过一个称为 NSTextContentManager
的新对象。NSTextContentManager
对象将文本分成 NSTextElement
。当需要进行布局时,NSTextLayoutManager
会向 NSTextContentManager
获取 NSTextElement
。然后 NSTextLayoutManager
将 NSTextElement
布局到文本容器中,并生成包含布局和定位信息的 NSTextLayoutFragment
。当需要显示时,NSTextLayoutFragment
会传递给 NSTextViewportLayoutController
控制器,它会在你选择的渲染对象(无论是 View 还是 Layer)中处理这些片段的定位和布局。此过程涉及许多新对象。这也是强调值语义的地方,我们可以通过在正确的时机( delegate 方法)进行更改,创建新的对象实例并将它们返回给系统,系统使用替换对象来进行布局和显示。
NSTextElement
是文档的构建块,每个 NSTextElement
代表内容的一部分,并包含描述它在文档中的位置的范围。NSTextElement
具有值语义。它们的属性(包括范围)是不可变的,并且在创建后无法更改。将文档建模为一系列 NSTextElement
而不是字符给了我们更高的自由度。我们能够轻松区分给定元素代表的内容类型,是一段文本、附件还是其他一些自定义类型以便我们可以根据元素的类型决定如何布置元素。
NSTextContentManager
知道如何从文本内容生成 NSTextElement
并在整个文档中并且追踪这些元素的使用。NSTextContentManager
提供了将原始数据转换为 NSTextElement
的接口。NSTextContentManager
和 NSTextElement
都是抽象类型,如果需要使用自定义文档模型可以对它们进行子类化操作。但大多数情况下,你可以直接使用 TextKit 2 提供的默认设置。
NSTextContentStorage
是一个使用 NSTextStorage
作为存储的内容管理器。它知道如何将文本存储的内容划分为段落元素,这些元素也就是 NSTextParagraph
的实例。NSTextContentStorage
还知道如何在文本发生变化时生成更新的段落元素。
在对文本进行更改时,应该将更新包装在 performEditingTransaction 方法中。这可确保 TextKit 2 系统的其他部分感知到变化。
NSTextLayoutManager
与 TextKit 1 中旧的 NSLayoutManager
类似,但 NSTextLayoutManager
不处理字形。并且 NSTextLayoutManager
可以获取文本元素,并将它们布置到文本容器中,并为这些元素生成布局片段信息 NSTextLayoutFragment
。
NSTextLayoutFragment
包含一个或多个文本元素的布局信息。它们使用值语义并且它们的属性是不可变的。NSTextLayoutFragment
通过三个属性传达布局信息:textLineFragments 数组、layoutFragmentFrame 和 renderingSurfaceBounds 方法。如果你想自定义或更改布局,可以从这几个方法入手。
如下的代码示例,我们可以添加在文字布局外层添加一个气泡的背景:
class BubbleLayoutFragment: NSTextLayoutFragment {
// 返回渲染布局范围
override var renderingSurfaceBounds: CGRect {
return bubbleRect.union(super.renderingSurfaceBounds)
}
// 气泡绘制的实现
override func draw(at renderingOrigin: CGPoint, in ctx: CGContext) {
ctx.saveGState()
let bubblePath = createBubblePath(with: ctx)
ctx.addPath(bubblePath)
ctx.setFillColor(bubbleColor.cgColor)
ctx.fillPath()
ctx.restoreGState()
super.draw(at: renderingOrigin, in: ctx)
}
}
那么我们可以从哪个时机给系统我们自定义的 NSTextLayoutFragment
呢?答案是在 NSTextLayoutManagerDelegate
协议中。
代码示例:
func textLayoutManager(_ textLayoutManager: NSTextLayoutManager,
textLayoutFragmentFor location: NSTextLocation,
in textElement: NSTextElement) -> NSTextLayoutFragment {
// Something Code
return NSTextLayoutFragment(textElement: textElement, range: textElement.elementRange)
}
}
以上的部分就是 TextKit 2 在安全性方面的工作。
高性能是任何文本引擎面临的最大挑战之一。TextKit 2 在日常生活的场景中速度非常快,从快速渲染只有几行的标签到以交互滚动数百兆字节的文档布局中都可以体现。对于这些场景,当你用可变速率滚动浏览这些非常大的文档时,不连续的文本布局对于性能来说绝对是必不可少的。
连续和非连续布局之间的区别是什么呢?用2张图来说明一下
在可视的范围之外,布局依然存在,这个叫做连续的布局。
只在可视的范围之内的布局,打破文档布局结构,这个叫做不连续的布局。
在 TextKit 2 中的布局总是不连续的。仅对屏幕上可见的文本部分执行布局以及额外的过度滚动区域来提高性能,从而产生更流畅的滚动体验。相比之下,非连续布局在 TextKit 1 中是可选的。使用 TextKit 1,你只能打开或关闭非连续布局。在 TextKit 2 中你可以在视口布局之前、期间和之后收到回调做出对文字部分排版和布局。为了获得最佳性能,你的代码应专注于处理视口区域内的布局信息,尽可能去避免为视口外的元素请求布局信息。
NSTextViewportLayoutController
是可见范围布局的控制器对象,NSTextViewportLayoutController
在视口布局过程中对其 Delegate 调用三个重要方法:TextViewportLayoutControllerWillLayout
、textViewportControllerConfigureRenderingSurface
和 textViewportLayoutControllerDidLayout
。你可以在 TextViewportLayoutControllerWillLayout
执行任何准备工作以准备布局,例如清除视图或图层的内容。在处理布局中,NSTextViewportLayoutController
为视口中可见的每个布局片段调用 textViewportControllerConfigureRenderingSurface
方法来达到渲染的目的。最后,NSTextViewportLayoutController
在完成对视口中可见的所有布局片段的布局后调用 didLayout 方法,可以在此处执行任何所需的更新。
这就是 TextKit 2 对保持高性能所做的努力。
TextKit 2 所有新类都可以在 iOS 15 的 UIKit 和 macOS 12 的 AppKit 中使用,如果你想,今天就可以开始使用 TextKit 2 编写新代码。由于 TextKit 1 是内置文本控件不可或缺的一部分,所以系统组件也并非完全切换到 TextKit 2。下面是一些使用的注意事项:
更多详细的可以查看 Apple 的开发者文档:https://developer.apple.com/documentation/appkit/textkit/using_textkit_2_to_interact_with_text
TextKit 2 在今年给我们带来了大量更新。通过抽象字形的处理,让我们在处理多语言的情况下的得心应手避免了准确性的问题。通过对文档模型的抽象和计算布局流程的更新,赋予我们在整个文本渲染的流程中有更高的定制性,高效的实现我们对文本排版的自定义要求。高性能的秘密则是在只针对视野范围内的区域高效率的绘制,避免了视野外区域的排版和渲染的性能损耗,这也是让 TextKit 2 高效的原因。最后希望各位开发者可以利用 TextKit 2 的新特性,创造更多的创意和实现更酷炫效果。
在 Session 视频中带了一个 TextKit 2 的 Demo App,感兴趣的同学可以下载体验一下:https://docs-assets.developer.apple.com/published/fe5abca8d6/UsingTextKit2ToInteractWithText.zip?language=objc
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/vZ74jNgItabOB-TsaQn6Uw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。