在您呈现的结构中,使用 AutoLayout,您的 UIScrollView 的 contentSize 由其子视图的 intrinsicContentSize 驱动,这里是您的 SinglePostView。
问题是,SinglePostView 是UIView 的子类,它的intrinsicContentSize 在单独考虑时总是CGSizeZero。您需要做的是使您的SinglePostView 的intrinsicContentSize 依赖于其子视图的intrinsicContentSize。
那么,因为您的SinglePostView 的子视图是UILabels,并且因为UILabel 的intrinsicContentSize 是显示其内容所需的最小尺寸,所以您的SinglePostView 的intrinsicContentSize 将等于其子视图intrinsicContentSizes 的总和,即显示所有三个标签的内容所需的总大小。
这里是怎么做的。
第 1 步:删除所有自动设置的约束
首先,正如您部分所做的那样,您需要删除系统自动设置的所有约束。
假设您没有在情节提要或 XIB 中设置任何约束(或者您甚至没有这些约束),只需执行以下操作:
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
singlePost.translatesAutoresizingMaskIntoConstraints = NO;
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO;
contentLabel.translatesAutoresizingMaskIntoConstraints = NO;
现在您有了清晰的计划,您可以开始设置自己的约束条件了。
第 2 步:约束scrollView
首先,让我们像您一样创建视图引用字典以供 AutoLayout 使用:
NSDictionary *views = NSDictionaryOfVariableBindings(scrollView, singlePost, titleLabel, subtitleLabel, contentLabel);
然后,就像你已经做过的那样,让我们将滚动视图限制为其父视图的大小:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[scrollView]-0-|" options:0 metrics:0 views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[scrollView]-0-|" options:0 metrics:0 views:views]];
第 3 步:约束SinglePostView 推送scrollView 的contentSize
要清楚这一步,您必须了解在UIScrollView 和它的subviews 之间设置的每个约束实际上都会改变UIScrollView 的contentSize,而不是它的实际bounds。例如,如果您将UIImageView 约束到其父UIScrollView 的边界,然后将两倍于UIScrollView 大小的图像放入UIImageView,您的图像不会缩小,它是@987654355 @ 将采用其图像的大小并在 UIScrollView 内变为可滚动的。
所以你必须在这里设置:
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[singlePost]-0-|" options:0 metrics:0 views:views]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[singlePost]-0-|" options:0 metrics:0 views:views]];
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:singlePost
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:scrollView
attribute:NSLayoutAttributeWidth
multiplier:1.0f
constant:0.0f]];
前两个约束非常明显。然而,第三个在这里是因为,为了让您的 UILabels 正确显示其内容并且仍然可读,您可能希望它们是多行的并且滚动是垂直的,而不是水平的。这就是为什么您将SinglePostView 的width 设置为与scrollView 相同的原因。这样,您可以防止您的 scrollView 的 contentSize.width 超出其 bounds.width。
第 4 步:约束您的 UILabels 以“推动”您的 SinglePostView 的边界
第四步也是最后一步,您现在需要对SinglePostView 的子视图设置约束,以便从它们那里获得intrinsicContentSize。
这是你的做法(最简单的实现,没有边距,一个标签一个接一个垂直):
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[titleLabel]-0-|" options:0 metrics:0 views:views]];
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[subtitleLabel]-0-|" options:0 metrics:0 views:views]];
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentLabel]-0-|" options:0 metrics:0 views:views]];
[singlePost addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[titleLabel]-0-[subtitleLabel]-[contentLabel]-0-|" options:0 metrics:0 views:views]];
你应该完成了。
最后一个建议,您绝对应该查看UIStoryboard 来做这些事情。它更简单,更直观。
希望这会有所帮助,
P.S.:如果你愿意,我可以花一些时间在 Github 上同时使用 UIStoryboard 和 Visual Format Language 推送一个项目。只要告诉我你是否需要一个。
祝你好运。