通过在XCode中构建AirBnb应用程序来学习UIStackView

UIStackView仅在IOS 9.0中添加到Apple的UIKit中,使其成为该家族的最新成员(如果仍然是2015年)。这没关系……因为UIStackViews不仅在布局上是通用的,而且还没有得到应有的恕我直言,所以我们可以:

  • 构建复杂的布局,而不会使我们的View Controller过度拥挤
  • 在运行时更改布局,而无需进行繁琐的约束操作
  • 视图自动调整自身(即,如果您要添加动画)

让我们通过构建一个受AirBnb令人误解的复杂布局启发的简单页面来演示这一点:

使用堆栈视图构建页面的关键在于将布局分解为可堆栈的容器的能力。 没有将布局分解为堆栈的单一组合,因为此过程取决于页面的美学偏好。 例如,上面的示例页面包含嵌套的水平和垂直堆栈的层次结构。 首先,让我们关注红色容器中包含的堆栈。

注意适用于主图像下所有元素的左右边框。 可以在垂直堆栈的声明中实现此效果。 因此,进入“堆栈4”(带填充的垂直堆栈)的所有视图都不需要水平间距约束。 堆栈要求其包含的所有元素都具有固有的内容尺寸,除非堆栈受其父视图明确约束。

在进入“堆栈4”的所有视图中,只有三个是堆栈。 垂直堆栈中包含的其余视图将是视图本身。 这三个嵌套堆栈分别标记为“堆栈1”,“堆栈2”和“堆栈3”。

1.“堆栈1”(嵌套的水平堆栈)

  • “整个家”标签
  • “由dotcookiez托管”标签
  • 个人资料图片imageView

“堆栈1”由间距为3pt的常规垂直堆栈组成。 如图所示,需要左对齐以使标签保持左对齐。 使用我的AutoLayoutExtensions类,可以使用以下行完成此操作:

 让stack1a = verticalStack(.leading,间距:3,视图:homeLabel,hostedLabel) 

要将配置文件imageView与垂直堆栈组合,请使用返回的垂直堆栈和配置文件imageView创建一个水平堆栈。 请记住,必须限制个人资料图像的宽度和高度才能可见。

  profileImage.setWidthAndHeight(65,高度:65) 
让stack1 = horizo​​ntalStack(.center,间距:0.0,视图:stack3a,profileImage)

2.“堆栈2”(嵌套水平堆栈)

  • “ 5位客人”图标
  • “ 2个房间”图标
  • “ 3张床”图标
  • “ 2浴”图标

此嵌套堆栈由水平对齐并中心对齐的四个图标组成。 尽管将间距设置为0(默认间距值),但其宽度稍后会受到垂直堆栈的限制,因此只需确保等间距的中心对齐即可完成自动分配技巧。

  guests Icon.setWidthAndHeight(55,高度:55) 
roomsIcon.setWidthAndHeight(55,height:55)
bedsIcon.setWidthAndHeight(55,高度:55)
bathsIcon.setWidthAndHeight(55,height:55)
let stack5 = horizo​​ntalStack(.center,间距:0,views:guestIcon,roomsIcon,bedIcon,bathsIcon)

3.“堆栈3”(嵌套的垂直堆栈)

起初将一个垂直堆栈嵌套在另一个垂直堆栈中似乎是违反直觉的。 但是请注意,“堆栈3”内两个标签之间的间距与将要填充到垂直堆栈中的所有元素之间的间距不同。 为了模拟这种效果,我们将对该堆栈中的视图应用3pt的间距。

 让stack7 = verticalStack(.fill,间距:3,视图:aboutLabel,aboutText) 

4.“堆栈4”

  • “位于市中心的豪华公寓”标题标签
  • “堆栈1”
  • 分频器1
  • “堆栈2”
  • 分频器2
  • “堆栈3”

最后,所有视图(主图像除外)都将使用填充进入垂直堆栈。 再次记住,所有单个元素的尺寸必须明确,因此请在此处根据需要设置所有宽度和高度。 使用AutoLayoutExtensions的方法,将如下所示:

  divider1.setHeight(1)//宽度将受到带有填充的垂直堆栈的限制 
Divider2.setHeight(1)

/ *堆栈3 * /
让stack3 = verticalStack(.fill,间距:3,视图:aboutLabel,aboutText)/ *堆栈4-带填充的垂直堆栈* /
让stack4 = verticalStackWithPadding(.fill,间距:15,填充:UIEdgeInsets(顶部:0,左:20,底部:0,右:20),视图:titleLabel,stack1,divider1,stack2,divider2,stack3)

现在,我们将除主图像之外的所有元素都放入一个堆栈中,我们终于可以添加主图像了。 只需使用以下代码即可:

 让finalStack = verticalStack(.center,间距:15,views:mainImage,stack4) 

还记得我曾经说过,除非堆栈受到其父视图的显式限制,否则所有堆栈都要求其包含的所有元素都具有固有的内容尺寸? 由于我们在上方初始化的所有视图均取决于堆栈的水平约束(否则它们将不知道左右边界在何处),因此此最后一行将所有内容放置到位,并最终允许所有内容正确显示。