我是否遗漏了 Core Text 中的某些内容,这些内容可以让我看到某个点在哪一行,以及包含段落样式的一行到底有多高?

Am I missing something in Core Text that will let me see which line a certain point is in and how tall a line really is including paragraph styles?

所以我正在尝试编写一个自定义的 NSView,其中包含文本,但不使用 NSTextView(因为它不仅仅是文本)。我可以使用 Core Text 来绘制文本,但现在我还需要能够进行插入符号和 selection 矩形的命中测试和绘制。

绘制插入符和 selection 的简单方法,如各种 Apple 示例所示,是获取包含所需字符串范围的各种 CTLines 的印刷边界(使用 CTLineGetBoundsWithOptions(0) 而不是CTLineGetTypographicBounds() 由于后者的各种错误)并填充了结果矩形。不幸的是,一旦有任何类型的段落样式(无论是段落间距、行间距还是行高),它就会停止工作,因为段落样式 not 包含在印刷边界中。如果您 select 跨越多行的文本,您会在行与行之间看到有点标志性的白色间隙!这仍然没有回答如果我单击行之间的白色 space 如何知道要使用哪一行的问题。

由于 Core Text 默认情况下如何将指标点对齐到整数,在排版边界重叠或它们之间有间隙之后,我注意到如果我调用 CTFrameGetLineOrigins() 我可以确定行的高度 i + 1 通过计算 origins[i].y - origins[i + 1].y;第 0 行的高度是框架的高度减去组合的其他行的高度。这里使用 i + 1 很重要;它处理由 space 高度与其他字符高度不同的字体引起的奇怪情况。

但是,使用这种技术,我无法区分行上方的间距和行下方的间距,无论 space 是段落还是行 space。所有间距都被视为在线上方,如果使用多种间距模式,它们只是组合。我有 a small program,你可以用它自己试验一下;单击 "Baseline Diffs" 复选框以在行高中添加阴影。

所以问题是:无论段落样式如何,我都无法弄清楚一行到底有多高以及它的基线相对于它的高度的位置,我错过了什么?或者如果我想这样做,我需要自己重新实现Core Text的内部逻辑吗?我确实有很多作品在一起,但其中很多都是高度有条件的...

最后一段发生了什么?我应该在那里模拟尾随 space 吗?

解决方案需要 运行 OS X 10.8 或更高版本。

谢谢。

您需要问自己的一个大问题是您想要这些事情的结果。线的高度真的只是线的高度。它不包括行之间的间距。排字机不必将所有行都堆叠起来。考虑 two-column 行可能比前一行 更高 的布局情况。或者是否有分页符;您认为页面的边距是 line-height 的一部分吗? Core Text 不只是处理 "TextView-like things." 它处理相当任意的布局情况。

您 运行 陷入了一个难题,即两行之间的 space 应该属于哪一行。这是你要回答的问题。 Core Text 不知道你想要什么。它不知道任何这些矩形的含义,也不知道它们如何协同工作。

所以对于选择问题,是的,您需要通过创建所有完全选中的线矩形的并集(加上第一行和最后一行的额外位)来计算完整框。简单的 single-column 文本通常就是这样做的;显然,如果文本可以跨越多列,它会变得有点复杂。您可能还必须考虑文本流动 "backwards" 的情况(即 right-to-left 通常在 left-to-right 文本内)。

仅使用 low-level Core Text 基元需要大量工作。我会首先尝试使用 NSLayoutManager 来代替,看看它是否足以满足您的目的。如果您的问题只是您需要环绕(或跳过)图形或其他 non-text 元素,那么 NSLayoutManager 可能能够做 lot为你工作,让你照样用NSTextViewNSLayoutManager 可高度子类化以自定义其行为,使用它您通常可以保留 Cocoa 的 built-in 选择功能而无需重新实现它们。