控件的 frameForAlignmentRect 上的自动布局 setFrameSize

Auto Layout setFrameSize on control's frameForAlignmentRect

在 WWDC 2012 Session 228 视频 "Best Practices for Mastering Auto Layout" 中,它解释了 intrinsicContentSize 作为更好的 sizeToFit 并继续这个例子:

NSRect alignmentRect = (NSRect){NSZeroPoint, [control intrinsicContentSize]};
[control setFrameSize: [control frameForAlignmentRect:alignmentRect].size];

上面代码的目的是什么?

视频以“intrinsicContentSize 也适用于 springs-and-struts”开始该部分。因此,首先要了解的是,这部分内容是关于您使用自动布局的情况。

很好,因为在使用自动布局时不应使用 -setFrameSize:

因此,他们的意思是,与 sizeToFit 相比,从 intrinsicContentSize 开始可以更准确地确定控件的良好框架。对于许多控件,如果您调用 -sizeToFit,它们将使自己变得比容纳其内容(例如 pop-up 按钮菜单中菜单项的标签或标题)所必需的更大。他们解释说,由于二进制兼容性问题,即使 OS X 主题或艺术作品已更改,他们也无法使 sizeToFit 更好地工作。

intrinsicContentSize 是一个更好的工具,可以使控件的大小适合其内容,而不是更大。现在是这样,并且由于 intrinsicContentSize 没有二进制兼容性问题,即使主题和艺术作品发生变化,也将继续如此。

但是,固有大小是针对控件的对齐矩形。对于视图,有框架,然后是对齐矩形。框架必须足够大以包含视图所做的所有绘图,甚至是延伸到人们认为是其主要形状或大小之外的东西。 alignment rect 是自动布局系统对齐视图的边界。例如,如果视图有发光,则发光必须在视图的框架内,但应在其对齐矩形之外(因为其他视图不应与发光的限制对齐)。

他们将不得不将内部内容大小从对齐大小转换为框架大小。但是,从对齐方式转换为框架的唯一机制处理矩形 (NSRects),而不是大小 (NSSizes)。因此,他们构建了一个适当大小的矩形,对其进行转换,然后检查生成的矩形的大小。

他们创建了一个 NSRect,其原点任意位于 (0, 0),大小与控件的 intrinsicContentSize 相同。这就是 (NSRect){NSZeroPoint, [control intrinsicContentSize]} 的含义。那就是使用 C "compound literal" syntax 来制作 NSRect。请注意,这里假设控件在水平和垂直两个维度上都具有固有的内容大小。并非所有控件都这样做。有些人在一个或两个维度上使用 NSViewNoInstrinsicMetric/UIViewNoIntrinsicMetric,这种技术不适用于这些控件,至少在不进行一些调整的情况下是这样。

然后,他们将矩形从对齐矩形转换为框架矩形。他们必须要求控件进行此转换。对于某些控件,alignment rect 和 frame 可能相等;对于其他人,可能存在重大差异。只有该控件的实现才知道它的对齐矩形和它的框架应该如何关联。因此,您必须要求控件为您进行转换。这就是 [control frameForAlignmentRect:alignmentRect] 给你的。

现在你有了一个矩形框。起点基本上是任意的,因为您从 NSZeroPoint 开始。你不想control.frame = <the computed frame>。这会将控件移动到任意原点,而您不想这样做。您只想设置控件的大小,而不考虑其原点。因此,您从计算的框架矩形中提取大小。这就是 .size 访问在 [control frameForAlignmentRect:alignmentRect].size.

中所做的事情

最后,既然您有了新的控件大小,就可以在控件上进行设置了。也就是说,您将它传递给控件上的 -setFrameSize: 方法。现在该控件已根据需要调整其内容大小,但不会变大。