基于 `intrinsicContentSize` 的自动布局纵横比(非恒定)

Posted

技术标签:

【中文标题】基于 `intrinsicContentSize` 的自动布局纵横比(非恒定)【英文标题】:Autolayout aspect ratio based on `intrinsicContentSize` (not constant) 【发布时间】:2015-04-29 09:44:53 【问题描述】:

是否可以使用基于intrinsicContentSize 动态计算的纵横比来应用此类自动布局约束? 在文档中,我发现只有具有固定比率值的约束。

intrinsicContentSize 的实际高度和高度在我的用例中并不重要,我想保留动态变化的视图的高度和宽度比。

我应该提供我自己的约束实现吗?还是有更好的办法?

【问题讨论】:

【参考方案1】:

intrinsicContentSize 不可用作约束的输入。 (从逻辑上讲,实现intrinsicContentSize 和相关的内容拥抱和抗压缩优先级存在一些约束,但这是不同的。)

如果您想要这样的纵横比约束,您必须自己添加它。在给定时刻查询intrinsicContentSize 很容易,验证它是否为两个维度提供了真实值(不是NSViewNoInstrinsicMetric),计算纵横比,然后将其用作与项目宽度相关的约束中的乘数到它的高度。

困难的部分是知道intrinsicContentSize 何时失效,以便您可以删除旧的纵横比约束并添加一个新约束。您可以通过覆盖-invalidateIntrinsicContentSize 将其作为视图的子类来实现。 (一定要打电话给 super!)但是,我不知道有什么方法可以从控制器或超级视图中做到这一点。

【讨论】:

【参考方案2】:

您可以找到有关如何设置基于比率的约束here 的答案。您只需将宽度和高度限制在一起,同时保持给定的纵横比(在这种情况下为 4/3)。

我们可以争论视图知道这些信息是否是一件好事,或者他们的父母是否应该设置这种约束。我通常更喜欢父母设置约束,但是如果你的视图没有任何意义没有这个约束或者所有这些视图都需要这个约束,你可以安全地让这些视图管理它们自己的宽度/高度比。

最后,intrinsicContentSize 告诉 Auto Layout 当视图是单独的时视图的大小

返回接收视图的自然大小,仅考虑视图本身的属性。

我不知道你的观点代表什么,但正如文档所说,你可以返回CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric)

如果自定义视图没有给定维度的固有大小,它可以返回该维度的 UIViewNoIntrinsicMetric。

【讨论】:

【参考方案3】:

如果你有想在运行时计算约束值的情况,最好的选择是CTRL将约束拖到控制器的.h文件中并创建一个IBOutlet为了它。这允许您更改代码中约束的值。您甚至可以对约束值的更改进行动画处理。

然后在您的代码中,在设置时或发生可能更改您想要的值的操作(例如加载新图像)时,您计算您想要的约束值并在代码中设置它的值。通常你会这样做:

self.myConstraintIBOutlet.constant = <insert your new value>;

然后您可能需要将受影响的视图标记为需要布局:

// Mark whole view as needing layout. You could do this in a subview if
// only a small area is affected
[self.view setNeedsLayout];
[self.view layoutIfNeeded];

如果你想要一个平滑的过渡,你可以把layoutIfNeeded放在一个动画块中,让它动画约束的变化:

[self.view setNeedsLayout];
[UIView animateWithDuration:.25 animations:^
            [self.view layoutIfNeeded];
         completion:^(BOOL finished) 
            // Completion code
        ];

【讨论】:

这部分对我来说很明显。但是我在哪里连接这段代码呢?什么时候应该调用self.myConstraintIBOutlet.constant = self.someView.intrinsicContentSize.height / self.someView.intrinsicContentSize.width;。它应该在所有视图布局更新之前。 如果它只发生在第一次显示时,viewWillAppear 将是一个起点,因为此时视图具有它们的大小。如果您稍后将其留给viewDidAppear,您会看到布局更改,这可能看起来像一个小故障。 如果您在更改文本或按钮标签等更改后需要它发生,然后在更改影响您更改某些内容的视图后执行它。这可能需要您进行更改,强制更改视图上的布局,然后更改约束,现在更新的宽度/高度已知,然后再次布局。 对于纵横比约束,纵横比值不在约束的constant中,而是在multiplier中。创建约束后,您无法更改其multiplier @KenThomases 是的,这是正确的。选项是每次用一个新的约束替换约束,或者假设宽度/高度之一已知,则根据计算的纵横比设置高度和宽度。需要知道确切的用例。对于替换,IBOutlet 可用于识别原件,然后从那时起使用替换件。这样一来,故事板将保持快乐,并且不会添加任何自动约束。

以上是关于基于 `intrinsicContentSize` 的自动布局纵横比(非恒定)的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 没有按时调用intrinsicContentSize

UIStackView自己的intrinsicContentSize

修改 `UITableView` 和 `UICollectionView` 的 `intrinsicContentSize` 方法可以吗?

Swift3 - UICollectionViewCel 的 intrinsicContentSize 是 (-1, -1)

如何在 iOS 11 上修复 UILabel intrinsicContentSize

navigationBar.IntrinsicContentSize.height 与实际栏的大小不匹配