翻译:swift 5 iOS的UIStackView教程:堆栈视图简介

说明

更新说明:Ehab Amer已针对Swift 5,iOS 12和Xcode 10更新了本教程。Jawwad Ahmad撰写了原文。

您是否曾经需要在运行时期间从视图中添加视图或从视图中删除视图,并调整视图旁边的视图布局?也许您调整了一些约束或使用了第三方库来完成这项工作。也许不是在运行时运行,而是您想在情节提要中的其他视图之间添加一个新视图。

在这些情况下,您需要更改几个约束。您可能会发现自己删除了该区域中的所有约束,然后又重新添加了它们。

UIStackView简化了此类任务。您可以轻松地在堆栈视图中水平或垂直放置一系列视图,并通过对齐,分布和间距等属性将视图自动调整为可用空间的方式进行设置。请享用!:]

注意:本教程假定您基本熟悉自动版式。如果您不熟悉自动版式,请查看“AutoLayout开始自动版式”视频教程。

入门

首先使用本教程下载项目材料。使用iPhone 8 Simulator在Xcode中构建并运行starter项目。您会看到以下内容:

在这里插入图片描述
这是假期景点应用程序。它提出了一个摆脱一切的地方清单。在前往任何地方之前,您将使用Stack Views解决该应用程序的一些问题。

探索度假胜地

去伦敦的信息视图通过点击伦敦。乍一看,该视图可能看起来不错,但存在一些问题:

  1. 查看视图底部的按钮行。由于它们之间的间距固定,因此它们无法适应屏幕宽度。为了更好地解决问题,请按Command-左箭头将模拟器旋转为横向。
    在这里插入图片描述
  2. 点击“天气”旁边的“隐藏”。这将隐藏文本,但不会重新定位其下面的部分,而是留出一块空白。
    在这里插入图片描述
  3. 节订购需要改进。这将是更符合逻辑的,如果看到什么后出现为什么参观定位它们之间的天气部分代替。
  4. 在横向模式下,按钮的底行太靠近视图的底部边缘。如果减小各部分之间的间距,则效果会更好-但仅在横向模式下。

既然您已经知道将要进行的改进,那么现在该深入研究该项目了。打开Main.storyboard。它将以初始设备视图打开。确保将iPhone 8显示为所选设备。
在这里插入图片描述
这在运行时没有影响,但可以帮助您查看屏幕在该设备上的外观。您可以随时单击另一个图标来更改所选设备。将鼠标悬停在图标上可以显示其相应的设备。
在这里插入图片描述
注意:如果减小Interface Builder的画布宽度(大约小于650像素),则用于更改设备的UI会稍有变化。设备列表折叠到设备下拉列表中:
在这里插入图片描述
当按下时,将显示垂直排列的可用设备列表:
在这里插入图片描述
现在,仔细查看Spot Info View Controller:
在这里插入图片描述
您可能想知道颜色是什么?

这些标签和按钮的背景色在运行时不会显示。在情节提要中,它们是视觉辅助工具,有助于显示更改堆栈视图的各种属性如何影响其嵌入式视图的框架。

如果您希望在运行应用程序时随时查看背景颜色,则可以暂时将viewDidLoad()里面的以下行注释掉SpotInfoViewController。

// Clear background colors from labels and buttons
for view in backgroundColoredViews {
    
    
  view.backgroundColor = UIColor.clear
}

任何与插座连接的标签均具有与插座变量名称匹配的占位符文本。这样可以更轻松地确定在运行时将更新哪些标签的文本。例如,带有文本< whyVisitLabel>的标签连接到:

@IBOutlet var whyVisitLabel: UILabel!

是时候开始了!

您的第一个堆栈视图

首先,您将固定底部一行按钮之间的间距。堆栈视图可以通过各种方式沿其轴分布其子视图。一种方法是在每个视图之间设置相等的间距。
在这里插入图片描述
幸运的是,将现有视图嵌入到新的堆栈视图中可谓小菜一碟。首先,通过单击一个,然后在其他两个上单击命令,选择“ Spot Info View Controller”场景底部的所有按钮。使用情节提要画布左下角的“显示文档大纲”按钮打开大纲视图。
在这里插入图片描述
确认您已选择所有三个按钮。
在这里插入图片描述
它们在大纲视图中突出显示。您也可以在大纲视图中单击命令的每个按钮以选择它们。

选择后,在情节提要画布右下角的“自动布局”工具栏中单击“嵌入”按钮。出现带有可用嵌入选项的菜单。选择堆栈视图:
在这里插入图片描述
Xcode将为您将按钮嵌入新的堆栈视图中。

在这里插入图片描述

堆栈视图约束

尽管堆栈视图负责放置按钮,但是您仍然需要添加自动布局约束来定位堆栈视图本身。

当您将视图嵌入堆栈视图时,它将失去对其他视图的约束。例如,在将按钮嵌入到堆栈视图中之前,“提交评分”按钮的顶部与RATING标签的底部之间存在垂直间距约束:
在这里插入图片描述
选择“提交评分”按钮,并验证它不再具有任何约束:

在这里插入图片描述
您还可以查看大小检查器(Option-Command-5)以验证是否没有约束:
在这里插入图片描述
有时很难在拥挤的情节提要的视图控制器中选择特定元素。您可以从大纲视图中选择元素,或使用Shift并在要选择的视图上单击鼠标右键或按住Control键并按住Shift键单击。这为您提供了一个上下文菜单,该菜单显示了单击位置的视图层次结构。通过在菜单中单击选择堆栈视图。
在这里插入图片描述
既然已经选择了“堆栈视图”,则可以向其添加约束。
在这里插入图片描述
单击自动版式工具栏中的“添加新约束”按钮以显示“添加新约束”弹出窗口。
在这里插入图片描述
首先,在Constrain to margins上添加一个选中标记。然后,将以下约束添加到堆栈视图的边缘:

Top: 20, Leading: 0, Trailing: 0, Bottom: 0

仔细检查顶部,顶部,底部和底部约束的数字。确保您已打开四个红色工字梁并限制到边距。然后,点击添加4个约束。
在这里插入图片描述
现在,堆栈视图的大小正确,但是它拉长了第一个按钮以填充任何额外的空间。

在这里插入图片描述

堆栈视图外观

确定堆栈视图如何沿其轴布置其子视图的属性为distribution。当前,它设置为Fill,这意味着子视图将沿其轴完全填充堆栈视图。为此,堆栈视图将仅扩展其子视图之一以填充该额外空间。具体来说,它会以拥有最低优先级的水平内容来扩展视图,或者如果所有优先级都相等,则会扩展第一个视图。

但是,您不希望按钮完全充满堆栈视图,而是希望它们之间的间距相等。

确保堆栈视图仍处于选中状态,然后转到“属性”检查器。更改分配从填充到间距相等:
在这里插入图片描述
现在构建并运行,点击任意一个单元,然后旋转模拟器。您会看到底部按钮现在的间距相等!
在这里插入图片描述

在这里插入图片描述
实施UI时,请始终问自己元素是否适合可用空间。

这是您的内容如何影响用户体验的示例:将Wikipedia按钮的标题更改为Wikipedia网站并运行该应用程序。将模拟器从纵向旋转到横向以查看差异。
在这里插入图片描述
在这里插入图片描述
在空间较窄的纵向模式下,最后一个按钮中的文本会被剪切,而在横向模式下,所有内容都适合。

这是您经常遇到的事情,尤其是在iPhone SE等较窄的屏幕尺寸上。

幸运的是,这很容易解决。在仍然选择堆栈视图的情况下,返回Attributes inspector。将分布从等间距更改为按比例填充,并将间距值更改为10:
在这里插入图片描述
现在,构建并运行并检查两个方向。您会按顺序找到所有内容。
在这里插入图片描述
将按钮的名称更改回Wikipedia。

恭喜,您已经建立了第一个堆栈视图!

没有堆栈视图

为了在没有堆栈视图的情况下解决此间距问题,您将必须在每对按钮之间使用一个间隔视图,向所有间隔视图添加相等的宽度约束,以及几个其他约束以正确放置间隔视图。

这看起来类似于以下内容。为了在屏幕截图中可见,间隔视图显示浅灰色背景:
在这里插入图片描述
如果您必须在情节提要中执行一次操作并不太麻烦,但是许多视图是动态的。由于相邻的间隔视图和约束,在运行时添加新按钮或隐藏或删除现有按钮不是一项简单的任务。

为了在堆栈视图中隐藏视图,请将包含的视图的hidden属性设置为true,然后堆栈视图将处理其余视图。这是当用户将文本隐藏在WEATHER标签下时固定其间距的方法。将天气部分标签添加到堆栈视图后,即可在本教程中进行操作。

注意:现在您知道如何在堆栈中指定子视图之间的间隔。但是,如果您想要在特定子视图后使用不同的间距怎么办?从iOS 11开始,您可以使用setCustomSpacing:afterView进行此操作

转换节

接下来,您将转换所有其他部分SpotInfoViewController以使用堆栈视图。这使您能够完成其余任务。从评分部分开始。

转换评级部分
在您创建的堆栈视图上方,选择“评分”标签和旁边的星号标签。

然后,单击编辑器▸嵌入▸堆栈视图中。

现在,选择新创建的堆栈视图,然后再次单击“添加新约束”按钮。在约束到边距中打勾,并添加以下三个约束:

Top: 20, Leading: 0, Bottom: 20

在这里插入图片描述
现在转到“属性”检查器并将间距设置为8。

注意:您可能已经注意到,间距已经设置为8。以前,间距自动设置为24。Xcode变得足够聪明,可以推断出间距值以匹配嵌入视图之前的值。很酷吧?

生成并运行以验证所有内容与以前相同。

取消嵌入堆栈视图

在您走得太远之前,最好先进行一些急救培训,以防出现问题。例如,您可能会因为实验,重构或偶然而发现自己拥有额外的堆栈视图。

幸运的是,有一种简单的方法可以从堆栈视图中取消嵌入视图。

首先,选择要删除的堆栈视图。单击嵌入按钮。接下来,在出现的上下文菜单上选择“未嵌入”:
在这里插入图片描述
执行此操作的另一种方法是选择堆栈视图,然后从菜单中选择“编辑器”▸“未嵌入”。

创建垂直堆栈视图
现在,创建您的第一个垂直堆栈视图。选择“为什么访问”标签及其下方的,然后选择“嵌入在▸堆栈视图中”。

当您将标签嵌入堆栈视图中时,Xcode会根据标签的位置推断它应该是垂直堆栈。

较低的标签以前具有将其固定在右边距的约束,但是将标签嵌入堆栈视图中可以消除该约束。当前,堆栈视图没有任何约束,因此采用其最大视图的固有宽度。

选择堆栈视图后,单击“添加新约束”按钮。将顶部约束,前导约束和尾随约束设置为0。同样,请确保选中约束到边距。

然后,单击底部约束右侧的下拉菜单,然后选择WEATHER(当前距离= 20):
在这里插入图片描述
默认情况下,Interface Builder会向您显示到最近邻居的约束,对于底部约束,约束是距离15的“隐藏”按钮。您需要将该约束置于其下方的WEATHER标签。

最后,点击添加4个约束。您现在应该看到以下内容:

在这里插入图片描述
现在,您有了一个展开的堆栈视图,其右边缘固定在视图的右边距。但是,底部标签的宽度仍然相同。您将通过更新堆栈视图的alignment属性来解决此问题。

对齐属性

该alignment属性确定堆栈视图如何垂直于其轴布置其视图。对于一个垂直堆叠视图中,可能的值是Fill,Leading,Center,和Trailing。

水平堆栈视图的可能alignment值略有不同:

在这里插入图片描述
水平堆栈视图具有.top而不是.leading和具有.bottom而不是.trailing。也有两个属性,只有在水平方向上是有效的,.firstBaseline和.lastBaseline。

选择每个值以查看它如何影响垂直堆栈视图中的标签放置:

Fill:
在这里插入图片描述
Leading:
在这里插入图片描述

Center:
在这里插入图片描述

Trailing
在这里插入图片描述

测试完每个值后,将Alignment设置为Fill:
在这里插入图片描述
生成并运行以验证一切看起来都不错,并且没有回归。

指定Fill意味着您希望所有视图都填充垂直于其轴的堆栈视图。这也会导致WHY VISIT标签也扩展到右边缘。

如果您只希望底部标签扩展到边缘怎么办?

目前,这并不重要,因为两个标签在运行时都具有清晰的背景,但是在转换天气部分时将很重要。

您将学习如何使用附加的堆栈视图来实现这一点

转换看什么部分

转换此部分与您已经完成的操作类似。

  1. 首先,选择要查看的标签,然后选择其下方的< whatToSeeLabel>。
  2. 单击“嵌入”按钮,然后选择“堆栈视图”。
  3. 单击固定按钮。
  4. 选中约束到边距并添加以下四个约束:
Top: 20, Leading: 0, Trailing: 0, Bottom: 20
  1. 将堆栈视图的Alignment设置为Fill。

现在,您的情节提要板应如下所示:
在这里插入图片描述这使您仅剩下天气部分。

转换天气部分

由于“隐藏”按钮,天气部分比其他部分更为复杂。

要转换天气部分,您可以通过将WEATHER标签和Hide按钮嵌入水平堆栈视图中来创建嵌套堆栈视图。然后,将该水平堆栈视图和< weatherInfoLabel>嵌入到垂直堆栈视图中。

它看起来像这样:

在这里插入图片描述
请注意,“天气”标签已扩展为等于“隐藏”按钮的高度。这将在WEATHER标签的基线与其下方的文本之间留出额外的空间。

请记住,它alignment指定垂直于堆栈视图的位置。因此,您可以将设置alignment为Bottom:

在这里插入图片描述
但是,您不希望“隐藏”按钮的高度决定堆栈视图的高度。

相反,您将从所有堆栈视图中删除“隐藏”按钮。

“隐藏”按钮将保留在顶层视图的子视图中,您将向其添加约束到WEATHER标签中-该标签将在堆栈视图中。没错,您将从堆栈视图外部的按钮向堆栈视图内的标签添加约束!

选择WEATHER标签并在其下方选择< weatherInfoLabel>,然后将它们堆叠在Stack View中。

单击添加新约束按钮,选中约束到边距并添加以下四个约束:

Top: 20, Leading: 0, Trailing: 0, Bottom: 20

将堆栈视图的Alignment设置为Fill:

在这里插入图片描述
您需要在“隐藏”按钮的左边缘和“ WEATHER”标签的右边缘之间有一个约束,因此让“ WEATHER”标签填充堆栈视图将不起作用。

但是,您确实希望底部的< weatherInfoLabel>填充堆栈视图。

您可以通过仅将WEATHER标签嵌入到垂直堆栈视图中来完成此操作。请记住,alignment可以将垂直堆栈视图的设置为.leading,并且如果将堆栈视图拉伸到其固有宽度之外,则其子视图将保持与前端对齐。

使用文档大纲或使用Control-Shift-click方法选择“天气”标签。然后,将其嵌入到新的堆栈视图中。

将Alignment设置为Leading,并确保Axis设置为Vertical:
在这里插入图片描述
完善!外部堆栈视图正在拉伸内部堆栈视图以填充宽度,但是内部堆栈视图允许标签保持其原始宽度!

生成并运行。哦哦 为什么“隐藏”按钮在文本中间挂出?
在这里插入图片描述
将WEATHER标签嵌入堆栈视图时,该标签和“隐藏”按钮之间的所有约束均被删除。

要添加新的约束,请按住Control键并将“ Hide”按钮拖动到WEATHER标签。

按住Shift键选择多个选项,然后选择“水平间距”和“第一基线”。然后按Enter,或在弹出视图之外的任何位置单击:
在这里插入图片描述
生成并运行。现在应正确放置“隐藏”按钮。由于设置为隐藏的标签嵌入在堆栈视图中,因此按“隐藏”可隐藏标签并调整其下方的视图-所有这些都无需手动调整任何约束。
在这里插入图片描述

在这里插入图片描述现在,所有部分都位于唯一的堆栈视图中,您可以将它们嵌入到外部堆栈视图中,这将使最后两个任务变得微不足道。

顶层堆栈视图

单击命令以在大纲视图中选择所有五个顶级堆栈视图。

然后将它们全部嵌入一个Stack View中:
在这里插入图片描述
单击“添加新约束”按钮,选中“约束到边距”,并将约束0添加到所有边。然后将Spacing设置为20并将Alignment设置为Fill。现在,故事板场景应如下所示:
在这里插入图片描述
构建并运行:

在这里插入图片描述哎呀!当将WEATHER堆栈视图嵌入到外部堆栈视图中时,似乎hide按钮再次失去了约束。没问题,只需以与以前相同的方式再次向其添加约束:

  • 按住Control键并将其从“隐藏”按钮拖动到WEATHER标签。
  • 按住Shift键。
  • 选择水平间距和基线。
  • 按Enter,或在弹出视图之外的任何位置单击。

生成并运行。该隐藏按钮现在是在正确的位置。

重新定位视图

现在所有的部分都在顶层堆栈视图中,您将修改的位置看什么部分,因此,它的上面天气部分。

从大纲视图中选择中间堆栈视图,然后将其拖动到第一视图和第二视图之间。

注意:将指针保持在您要在其间拖动的堆栈视图的左侧,使其仍然是外部堆栈视图的子视图。蓝色小圆圈应该在两个堆栈视图之间的左侧,而不是右侧:

在这里插入图片描述

尺寸等级配置

最后,将注意力转移到列表上剩下的一项任务上。在横向模式下,垂直空间非常宝贵,因此您希望将堆栈视图的各个部分放在一起。为此,您将使用大小类将顶级堆栈视图的间距设置为10,而不是垂直大小类为紧凑时的20。

选择顶层堆栈视图,然后在“属性”检查器中,单击“间距”旁边的+按钮:
在这里插入图片描述
选择“任意宽度”和“紧凑高度”,然后选择“添加变化”。
在这里插入图片描述
在新的hC字段中将Spacing设置为10:
在这里插入图片描述
生成并运行。纵向模式下的间距应保持不变。旋转模拟器,并注意各部分之间的间距已减小,并且按钮现在从视图底部开始有足够的空间:
在这里插入图片描述
如果没有添加顶层堆栈视图,您仍然可以使用大小类将分隔五个部分的四个约束中的每个约束的垂直间距设置为10,但设置起来不是更好吗?在一个地方?

与时间相关的是更好的事情,例如动画!

动画

当前,该应用在隐藏和显示天气详细信息时非常跳动。您将添加一些动画来平滑过渡。

堆栈视图与UIView动画引擎兼容。这意味着对已布置的子视图的出现或消失进行动画处理就像isHidden在动画块内切换其属性一样简单。

更改isHidden已安排子视图的属性将更新其父堆栈视图的布局。如果该更新是在动画块中进行的,则如果您在动画块中自己更改了布局,则将是相同的。

现在该写一些代码了!打开SpotInfoViewController.swift并查看updateWeatherInfoViews(hideWeatherInfo:animated:)。

您将在方法末尾看到这些行:

weatherHideOrShowButton.setTitle(newButtonTitle, for: .normal)
weatherInfoLabel.hidden = shouldHideWeatherInfo

将它们替换为以下内容:

if animated {
    
    
  UIView.animate(withDuration: 0.3) {
    
    
    self.weatherHideOrShowButton.setTitle(newButtonTitle, for: .normal)
    self.weatherInfoLabel.isHidden = shouldHideWeatherInfo
  }
} else {
    
    
  weatherHideOrShowButton.setTitle(newButtonTitle, for: .normal)
  weatherInfoLabel.isHidden = shouldHideWeatherInfo
}

生成并运行,然后点击“隐藏”或“显示”按钮。动画版本不会更好吗?

除了在动画视图隐藏属性堆栈视图中包含的,你也可以在栈动画性能视图本身,比如alignment,distribution,spacing甚至axis。

然后去哪儿?

您可以使用本教程顶部或底部的“下载材料”按钮下载项目的完整版本。以下是一些需要进一步研究的资源:

参考

https://www.raywenderlich.com/2198310-uistackview-tutorial-for-ios-introducing-stack-views

猜你喜欢

转载自blog.csdn.net/zgpeace/article/details/113486816