在Interface Builder中布置动态UIScrollViews

如果您正在学习或已经使用iOS一段时间,您可能已经意识到使用UIScrollViews是构建甚至稍微复杂的UI的必要条件。 您可能还意识到,要使滚动视图及其内容与AutoLayout配合使用可能会非常痛苦。

在本文中,我将解释如何在界面生成器中布局滚动视图。 我们还将看到如何使可滚动区域动态化,以便它将可改变其大小以及所显示的内容。

我不会详细介绍滚动视图的真正含义以及它可以做什么和不能做什么。如果您想了解更多有关滚动视图的信息,请查看Apple文档或本教程。 就是说,关于滚动视图,我们必须了解一件事,它们需要某种方式来了解其内容大小。 内容大小是让滚动视图知道其水平和垂直滚动区域应多大的内容。 例如,如果将内容大小(宽度和高度)简单地设置为滚动视图的框架,则它将不会滚动任何内容……但是,如果内容高度大于scrollViews框架的高度,则它将垂直滚动。

现在您可能在想:“好吧,我明白了,滚动视图的内容大小决定了可滚动区域,但是我们如何设置此内容大小的宽度和高度?”。 好了,可以显式和隐式地设置内容大小。 明确设置此方法的一种方法是直接对内容的高度和宽度进行硬编码:

  scrollView.contentSize = CGSize(宽度:300,高度:900) 

这种做事方式既有趣又有趣,直到您意识到这不是我们想要的一切为止! 我们希望事情是动态的。 我们不一定知道内容的高度和宽度应该是什么,毕竟,这可能取决于设备的大小,方向或滚动视图实际显示的更改内容。 由于我们计划使用界面构建器和AutoLayout,因此我们希望通过设置约束来隐式设置滚动视图。

我们将使视图控制器的整个视图成为一个垂直滚动页面(这是滚动视图的常见用例)。 首先,我们将使用一个空的视图控制器“刷新对象库”并在其上拍一个滚动视图。 因此,将UIScrollView拖到视图控制器的视图上,并将其约束设置为其超级视图的边缘。

现在我们已经设置了scrollView,我们将把UIView作为子级添加到scrollview中。 此视图是“虚拟视图”,因为它仅用于布局目的。 不过,不要上当,这是一个非常重要的虚拟视图。 该视图用于确定我们喜欢的contentSize ,并包含我们希望在scrollView中显示的所有内容。 由于此视图非常重要,因此我们将其重命名并将其称为contentView

另一个非常重要的步骤是将内容视图的每个边缘固定到scrollView的边缘。 这些是“ 特殊”约束,它们使滚动视图知道该视图(内容视图)将用于确定内容大小。

添加这些约束后,您仍然应该会看到自动布局错误,如果您问自己为什么,我也不会怪您。 我们将内容视图固定在顶部,底部,前边缘和后边缘……为什么我们仍然遇到问题? 记得我们说过这些是“特殊”约束吗? 好吧,是的,AutoLayout与scrollViews的工作原理略有不同。 我们所做的就是告诉scrollView我们的内容视图将用于定义其contentSize,但是我们实际上并未定义内容大小。 实际的内容大小将由内容视图的高度和宽度确定。

由于目标是使屏幕垂直滚动而不是水平滚动,因此我们首先在内容视图上设置宽度约束。 此约束的目的是完全禁用水平滚动。 我们将从内容视图到滚动视图本身设置相等的宽度约束

有了这个约束,无论滚动视图占据整个屏幕还是仅占据一部分,滚动视图都知道其内容宽度将与框架的宽度完全相同。 我们仍应具有自动布局警告,因为我们尚未设置任何定义内容高度的约束。

只是为了使此工作正常进行,而不会引起界面构建器的任何投诉,让我们为内容视图的高度定义静态值。 为此,我们将对我们的内容视图应用高度限制1000(完全任意)。

恭喜你! 如果一切操作正确,您将不会再看到有关我们布局的警告。 但是,如果您注意到滚动视图继续向下经过主视图,您可能会感到恼火。 在界面生成器中延长主视图的长度是一个好主意,以便我们可以查看和操纵滚动视图的内容。 为此,我们将选择视图控制器(而不是其视图),然后转到属性检查器。 在这里,我们应该看到“模拟指标”列表,我们需要将“大小”字段从“推断”更改为“自由格式”。 这将使我们可以调整视图的高度,请记住,这些“ 模拟 指标 ”仅是在设计和布局界面时为我们提供帮助,实际上不会影响我们的应用程序。 接下来,转到视图控制器的大小检查器,并将高度设置为更适合此场景。 在我们的案例中,考虑到将其设置为内容视图的高度,将1000设置为完全有意义。

您已经创建了一个垂直滚动视图,并且如果您运行模拟器,则应该能够上下滚动(因为内容高1000点,这比主视图大!)。 您不会看到任何内容,但是应该看到右侧的滚动条指示符上下移动,并且视图的顶部和底部也应“反弹”。 在大多数情况下,我不太喜欢弹跳,因此我将转到属性检查器将其禁用

作为程序员,我们应该知道到目前为止,我们所做的对于大多数情况还是不够的。 毕竟,我们将内容视图的高度硬编码为1000点。 如果滚动视图中的内容更大或更小,它将被截断或不填充视图的长度。 在下一步中,我们将使垂直滚动区域动态化,以便内容的高度将定义内容视图的高度。

我们的下一步是制作“从内容视图的顶部边缘到底部视图的不间断的约束和视图 ”。 ?? 什么? 不间断的锁链? 如果这对您没有太大意义……请放心,我将向您展示整个链结的全部内容。 在继续制作滚动视图之前,请先停留片刻以了解一些自动布局概念,以了解它。

父视图的子内容以及该子内容的约束可以隐式定义父视图的大小 。 让我们看一个简单的UIView看看它是如何工作的。

首先,我们需要给此视图沿y轴的位置和沿x轴的位置。 我将视图水平和垂直放置在中间

如果您具有自动布局的经验,您将知道该视图的布局将是不确定的,直到我们定义其宽度和高度。 现在让我们给它任意宽度,比如200。

现在,无需设置约束来定义高度,而是添加一些内容并使用该内容来定义高度。 我们将从在视图中添加两个UILabel开始。

接下来,我们将两个标签水平居中,并将其中一个标签固定在视图顶部。

此后,我们将第二个标签销钉与另一个标签垂直300个点。 同样,我们会将这个标签固定在视图的底部。

应用这些约束后,您应该会看到一些漂亮的蓝线并意识到UIView的高度已定义!

我们创建了不间断的约束链,并且UIView现在仅根据标签的顶部到底部约束知道高度。 顺便说一句,您可以水平执行相同的操作来定义视图的宽度。

大! 既然您已经(希望)了解到可以通过其内容的布局来设置视图大小,那么让我们使用相同的概念来定义内容视图的高度。

首先,删除内容视图上的高度限制(我们获得了1000点)。 我们不再希望使用静态值设置可滚动区域。 接下来,将任何所需的内容添加到内容视图,只需确保每个元素都有定义的高度,宽度和水平位置。 然后,您可以从上到下进行一系列约束。

恭喜!! 您制作了具有动态高度的垂直滚动视图! 如果您仍然遇到问题,请参考以下疑难解答提示:

  • 进行约束时请耐心等待,直到您完成连接链的最终约束时,都会出现红色的自动布局问题
  • 确保内容视图中的所有元素都具有定义的高度,宽度和水平位置,我的UILabel示例如此简单的唯一原因是UILabel具有固有的contentSize,因此我只需要设置水平位置,然后设置链垂直约束。
  • 从简单的内容开始可能是一个好主意,这样您就可以习惯于形成一系列约束来定义内容视图的高度。
  • 确保您的scrollView和主视图之间的约束&&内容视图和scrollView之间的约束与我们在本教程前面部分所做的完全一样。