iOS开发-Storyboards入门教程

首先我们来大致了解下,Storyboard是什么?

  • Storyboard是iOS5中引入的,在近几年的 Xcode 更新中可以看出,苹果对 Storyboard 的开发力度也不断增强,添加了更多功能和特性,同时也让界面的开发和适配更方便。
  • Storyboard的本质是XML文件,它描述了窗体、组件以及Auto Layout 约束等信息,因此协作开发也不成问题。
  • Storyboard的优势就在与它把界面和代码分离,是界面逻辑更直观,代码更清晰、让开发者更专注业务代码,使开发效率更高。

在本教程中,你将学习如何在Storyboard中进行设计场景,连接视图控制器以及场景过渡,而无需编写任何代码。

StoryBoardiOS 5首次引入的一个令人兴奋的功能,它可以为开发者节约大量的UI构建时间。StoryBoard允许你在一个文件中创建和设计多个视图控制器和视图,也允许你创建视图控制器之间的场景过渡。

在使用StoryBoard之前,你必须有过使用xib文件(也就是NIB文件)的经验,或者其他可视化编程设计工具的经验,否则理解上可能有一定的难度,不过问题不大,苹果的设计一向都让人一目了然。

在上古iOS开发中,每个视图只能使用一个xib文件(例如,每个UITableViewCellUITableView或其他支持的UIView类型)。下图展示了StoryBoard的样子。它类似于你将在本教程中构建的结构:

你不用管这是应用是干啥的,但你可以看到它的场景和它们是如何联系的。接下来我们将用故事版称呼Storyboard。

在本教程中,我们将创建一个Ratings应用,这是一个用于显示玩家列表、他们玩的游戏和他们的技能评级的应用原型。你将学习使用故事板完成的常见任务,比如创建场景和连接视图控制器。无需一行代码就可以完成所有这些操作。

开始

这里我们提供一个压缩包。这里包含了初始项目和一个名为Images的文件夹,里面包含了你以后需要的资源。

现在,你可以使用我提供的初始工程,或者打开Xcode,使用单视图应用模板创建一个新的iOS应用都可。

如果选择自己创建,按照如下方式填写模板选项创建初始工程。

  • Product Name: Ratings.
  • Organization Name: Fill this in however you like.
  • Organization Identifier: The identifier you use for your apps.
  • Language: Swift.
  • User Interface: Storyboard.

确保已取消使用Use Core DataInclude Unit TestsUI Tests选项。

创建完成后,Xcode的主窗口应该是长这样的:

新项目由六个文件组成:

  • AppDelegate.swift
  • SceneDelegate.swift
  • ViewController.swift
  • Assets.xcassets
  • LaunchScreen.storyboard
  • Main.storyboard

在本教程中,你不需要修改swift文件中的任何内容,所以不要担心它们。

Deployment Info中的General设置下,取消选中iPad。本教程只是示范一个竖屏应用,找到Device Orientation,取消勾选Landscape LeftLandscape Right选项。

预览

在左侧导航栏里打开Main.storyboard,进入Interface Builder可视化编辑页面:

这里,我们看到一个包含空视图的单一视图控制器。从左边指向视图控制器的箭头表示它是这个故事板的初始视图控制器。稍后我们会进行详细讲解。

你可能会注意到,默认场景大小是4.7英寸的。Xcode默认会为故事板开启Auto LayoutSize Classes。它们允许你创建灵活的用户界面,可以轻松调整大小,这对于支持各种大小的iphone和ipad非常有用。

现在,我们要将场景大小更改为另一个设备,请单击故事板左下角的按钮。然后,你就可以从支持的所有设备尺寸中进行选择,从iPad Pro(12.9英寸)到iPhone 4s(3.5英寸),包括纵向和横向。

设计

要在故事板编辑器中设计布局,从对象库中拖拽控件并将它们放到场景中你想要的位置。你可以稍后更改它们的位置或删除它们。

本教程中你将依赖对象库来设计故事板。在你开始使用这个应用程序之前,屏幕上还有一个项目你需要知道:Document Outline(也就是文件导航栏和可视化编辑器中间那栏),长下面这样:

Document Outline显示了你在当前打开的故事板文件中拥有的所有项目,以及任何视图控制器和它包含的任何控件。视图控制器在故事板上称为scene即场景。在本教程中,你将使用scene来引用故事板中的视图控制器。

Document Outline将是选择故事板元素的主要导航点操作之一。

现在,是时候开始构建Ratings应用程序了。

Document Outline下面我们将简称为视图结构栏。

Tabbar

我们将要构建的应用程序,有一个带有两个场景的选项卡界面。要添加选项卡界面,首先打开Main.storyboard和删除那里唯一的场景。只需点击视图结构栏中的视图控制器,并按下键盘上的删除键。

Tab Bar Controller从对象库(Object Library)拖到画布上。你可以通过输入关键字来进行控件筛选。

Tab Bar Controller预先配置了两个额外的视图控制器,每个标签一个。它是所谓的容器视图控制器,因为它包含一个或多个其他视图控制器。其他常见的容器是Navigation ControllerSplit View Controller

Tab Bar Controller和它包含的视图控制器之间的箭头表示容器关系。下图中箭头中间的图标表示它们具有嵌入关系。

以下Tab Bar Controller我们将简称为标签控制器,如果你想移动标签栏控制器和它附加的视图控制器作为一个组或者缩小,然后按住Command然后选择对应的视图控制器顶部,如此来选择多个视图控制器,(或者你要操作熟练,先缩小整个布局,然后用鼠标拖拽多选的方式更简单一点)。这让你可以一起移动它们。细细的蓝色轮廓表明您所选择的场景。

编译运行,你将在控制台中看到类似这样的⚠️内容:

1
Ratings[9912:704408] [WindowScene] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' – perhaps the designated entry point is not set?

不用方!这个警告仅仅表明应用程序没有找到初始的视图控制器来显示。在修复这个问题之前,花点时间了解一下发生了什么。

Error

首先,错误消息明确地提到了故事板的名称Main。它不是关键字,Xcode怎么知道它应该在应用开始加载这个故事板文件呢?

为了理解这一点,我们可以通过从项目导航栏Project Navigator中选择项目文件,从Targets列表中选择Ratings并确保选择了顶部的General选项卡来打开应用程序设置。

在这个设置里,我们将看到主界面(Main Interface)选项的下拉列表中的值是Main(这个下拉框将只显示项目中的故事板文件)。

初始控制器

保持Main作为选中值,并进行下一步:确定你想在故事板中开始的特定视图控制器。

打开Main.storyboard故事板并选择标签栏控制器场景。在右侧,选择Attribute inspector

然后选中Is Initial View Controller属性。

选中这个框将视图控制器作为你所在的故事板的初始入口点。同样,一个箭头会出现在视图控制器的左边。

现在,编译运行,你会看到一个空的视图控制器,有一个标签栏,底部有两个项目。

另一种改变初始视图控制器的方法是在视图控制器之间拖动初始指向箭头。

Xcode提供了一个用于构建选项卡应用的模板:选项卡应用模板。您可以在这里使用它,但最好知道如何自己构建一个,以便在必要时可以手动创建选项卡栏控制器。

如果你连接超过五个场景到标签栏控制器,它会自动添加更多的标签,当你运行应用程序就会看到。

设计列表

现在是时候在你的应用程序中构建第一个屏幕场景了。目前,附属于标签栏控制器的两个屏幕场景都是UIViewController实例。你要用UITableViewController代替第一个tab场景。

点击视图结构栏中的第一个视图控制器来选择它,然后删除它。拖动一个新的表视图控制器(UITableViewController)到画布上:

导航控制器

你想把表视图控制器放在导航控制器(UINavigationController)中。选择表格视图控制器,并从Xcode的菜单栏中选择Editor>Embed In>Navigation Controller。这将向画布添加另一个控制器

你可以从库中拖入导航控制器并嵌入表视图,但是对于一个常见的操作来说,这个嵌入命令可以很好地节省操作时间。

导航控制器也是一个容器视图控制器,它有一个关系箭头指向表格视图控制器。你可以在视图结构栏中看到:

注意,嵌入表格视图控制器给了它一个导航条。Interface Builder会自动把它放在那里,因为这个场景现在会出现在导航控制器的上下文中。

重连

删除第一个场景也删除了它与标签栏控制器的关系。但现在,你想重新创造它。你将把它连接到导航控制器场景,而不是连接到表格视图控制器场景。

要做到这一点,我们需要按住Control并在标签栏控制器场景上单击左键拖动,此时会出现一条连接线,直接连接到导航控制器。当你放手时,一个小的弹出菜单会出现。选择Relationship Segue-viewcontrollers选项:

这在两个场景之间创造了一个新的关系指向。这也是一个嵌入关系,就像你前面看到的那样。选项卡栏控制器有两个嵌入关系,每个选项卡对应一个。导航控制器本身与表视图控制器有嵌入关系。

创建这个新连接时,一个名为Item的新选项卡被添加到选项卡栏控制器中。对于这个应用程序,你想要这个新场景成为第一个标签,所以拖动标签来改变它们的顺序:

编译运行以看看。第一个选项卡现在包含了导航控制器中的一个表视图。

完善Tabs

在它们当前的状态下,标签根本不具有表现力。每个视图都应该有自己的图标和名称来代表它的视图。第一个标签的名字应该是Players,第二个应该是Gestures

当任何一个控制器连接到一个选项卡时,它会自动拥有一个UITabBarItem的实例。这个实例定义了出现在选项卡栏上的名称和图标。

在视图结构栏中,在Item 2场景下,你会发现一个名为Item 2的项目,它旁边有一个星形图标。选择它,并在Attributes inspector中将其标题更改为Gestures

现在,尝试另一种设置标题的方法。在导航控制器中,双击选项卡栏底部的Item,并键入新名称Players

现在可以添加图像了。从项目导航器中打开Assets.xcassets,然后拖拽Images文件夹到这个资源文件夹下。

回到故事板,使用属性检查器来更改两个选项卡项目的图像,你刚刚用它们匹配的图像重命名了它们。

看看我们刚刚设计完成的选项卡,so easy,你不需要一行代码就能做到这一点,而且这才刚刚开始。

单元格Table Cells

到目前为止,Players选项卡只显示了一个空列表,因为该屏幕中的table视图没有单元格。表视图有两种操作方式:

  • Dynamic prototypes允许您在故事板上构建单元格,以创建它们的多个副本。您只能通过代码实例化它们。
  • Static cells将完全按照您在故事板中设计的方式显示。它们不需要任何代码来实例化。

在大多数情况下,你将在应用程序中使用Dynamic prototypes,但由于本教程的目标是用零代码构建原型,所以您将使用静态单元格Static cells。不要担心,当开始构建代码时,很容易在它们之间切换。

选择table视图,并从Attributes Inspector中将Content下拉列表的值更改为Static Cells。现在,您可以自定义单元格。

自定义Cells

故事板现在在表格视图中显示了三个空单元格。继续并删除其中的两个。

选中仅剩下的Cell,修改其属性的Accessory的值为Disclosure Indicator

现在将Horizontal Stack View控件拖到单元格上。然后,在Horizontal Stack View中,添加一个Vertical Stack View和一个Image View。最后,在Vertical Stack View中添加两个UILabel

现在你的视图结构栏现在应该是这样的。

添加约束

经过上述一系列的操作过会,我们会毫无意外的收到一个警告,我们添加的视图不知道如何在单元格中定位自己。当你的应用程序运行在不同的设备上,不同的屏幕大小,单元格的大小会改变。这就是要使用Auto Layout的原因。

选中单元格中添加的水平堆栈视图,然后单击看起来像战斗机的Add New Constraints按钮。

该按钮将打开一个对话框,让我们指定约束值。指定要为堆栈视图添加的约束,如下所示:

四周的约束添加完成后,选择UIImageView并给它81的宽度限制。

当然,这里我们并不一定非要分成两步添加约束,熟练以后,你可以一步添加某个控件的大部分约束。

约束问题

对于我们添加的每一组约束,故事板上的控件都会调整它们的位置以匹配。

重要的是要避免任何布局错误,而现在,仍然有一个错误。有时候,Xcode能够建议你需要添加哪些约束条件来修复它。在这种情况下,这些建议是可行的,但个人经验,大部分时候自动添加的约束都跟你的需求相差甚远,所以我们还是要能熟练的使用约束和理解各种约束的含义和作用才能无往不利。

点击红色的约束错误提示小圆圈,它会显示布局错误。点击新建的红色圆圈,点击“更改优先级(Change Priority)”。

将下方标签的字体大小更改为14,并将Image view的图像设置为4Stars。然后,使用尺寸检查器Size inspector将表格视图中单元格的默认高度更改为60,并取消勾选表格视图和单元格的Automatic选项。

添加元素

当列表只有一个项目时,它就不是真正的列表。您可以复制刚才创建的单元格,也可以告诉表格视图显示更多。在本例中,我们执行后者。

从视图结构栏中选择Table View部分,并在属性检视器Attributes inspector中设置行数Rows3

最后一步是为单元格提供一些真实数据。输入一些人的名字和一些游戏,然后改变一些图片来给他们打分。不要忘记给这个屏幕一个标题:双击表格视图上方的空白区域,即导航栏区域,然后输入Players

编译运行,看看实际效果。

下一步是构建一个视图,让用户添加一个新的玩家。

构建添加玩家场景

如果没有代码,这个场景就不能正常工作,但是没有什么可以阻止我们为这些表单创建界面。

首先,你将在Players Scene的右上角添加一个+按钮。

在场景的右上角添加一个Bar Button Item。当你将按钮拖过该区域时,导航条会自动突出显示。然后,将其System Type更改为Add

添加按钮应打开一个带有表单的新场景,供用户输入玩家信息;接下来将创建该表单。

连接Segue

拖一个导航控制器Navigation Controller到你当前场景。它会附带一个表格视图控制器。然后,按住controlAdd按钮上拖动,将连线Segue拖动到新添加的导航控制器。从弹出菜单中选择Show

编译运行,然后点击Add按钮。

你会看到新的视图控制器从屏幕底部出现。当你从它的头部拖拽或滑动那个场景时,系统就会自动关闭当前模态视图。

你创建的从Add按钮到导航控制器的连接叫做Segue。因为它来自屏幕上的一个交互元素,也就是按钮,你可以通过点击它连接的按钮来触发场景切换Segue

苹果在iOS 13中引入了这种卡片式的交互演示。以前,任何像这样呈现的视图控制器都会占据全屏,你需要几行代码来关闭它。iOS 13不需要任何代码就能让东西看起来更好,这就是所谓的双赢!

构建表单场景

我们想要创建的表单应该如下所示:

在新创建的视图控制器中,在故事板中双击它的标题,并将其更改为Add Player。然后添加两个Bar Button Item,一个在左上角,一个在右上角。将左边的系统类型更改为Cancel,将右边的系统类型更改为Done

接下来,选择该场景中的Table View,将其内容更改为Static Cells,将Section更改为2。每个部分有三行。每个部分下只需要一个,所以删除最后两个。

最后,将表视图的样式更改为Grouped,将第一部分的标题更改为Player Name,并使用一个空字符串作为第二部分的标题。

编译运行,然后点击+按钮打开添加玩家表单。应该是这样的:

如果表视图的背景在改变了它的风格为Grouped后仍然是白色的,那么在属性检查器的视图部分改变它的背景颜色为默认,它应该回到浅灰色。

设计表单

第一部分中的单元格应该是一个文本字段Text Field。因此,在单元格上放一个文本字段。然后将该字段的边框样式Border更改为None

一旦更改了它的样式,文本字段的边框的控制角就会消失。手动设置它的大小以适应单元格,这里即便没有约束,它也能工作。

在创建的第一个表视图中,我们在单元格中添加了想要的每个元素。Xcode还为表格单元格提供了一些预设值供你选择。它们可能并不总是符合您的需求,但在一些简单的情况下,它们非常适合。

要尝试它们,请选择第二部分中的单元格,然后将其样式更改为Right Detail,并将Accessory更改为Disclosure Indicator。双击单词Title并将其替换为Game

编译运行并检查您的表单是否完全像这样:

接下来,我们填充游戏列表。

创建游戏列表

当你点击第二个单元格时,它会打开可供选择的游戏列表。这个列表应该是这样的:

这需要另一个表视图控制器Table View Controller,现在添加一个到故事板。将其表视图的内容Content更改为静态单元格Static Cells,并将其内部已经存在的单元格的样式Style更改为Basic。然后选择Table View部分,将Table View Section增加到6行。

将行标题更改为您喜欢的一些游戏,并将其中一个游戏的Accessory属性更改为Checkmark

到目前为止,这个场景还没有入口点;我们希望当点击“添加播放器”屏幕上的第二个单元格时打开它。为了实现这一点,我们需要像连接Add按钮到导航控制器一样连接场景。

按住control在第二个单元格到新场景。从弹出窗口中选择Show。

注意,在创建连接后,第二个场景中出现了一个后退按钮。这是因为这里的Show action会把第二个场景压入到导航控制器的逻辑堆栈里,导航控制器会自动提供一个后退按钮给任何额外的视图控制器。

编译运行。正如承诺的那样,你不需要一行代码就能完成这么多。

你知道故事板中也可以使用手势吗?

添加手势

手势是另一个可以直接在故事板上使用的控件。在本节中,你将学习如何像往常一样在没有任何代码的情况下使用它们。

在手势场景Gestures Scene中添加两个滑动手势Swipe Gesture Recognizers

这里注意一下,手势只能放到对应场景下的视图内才能正常工作。

在属性检查器Attributes inspector中,将第一个窗口的滑动Swipe方向设置为左,第二个窗口的滑动方向设置为右。

请注意,它们在视图结构栏中的名称是相同的,尽管它们有不同的方向。这使得如果添加太多相同手势,找起来有点困难。但是这不能保证你明天还能记住,所以我们应该咋整呢?

故事板标签

一个更好的名字会帮助你记住你的手势的作用。Xcode允许你改变出现在视图结构栏中的名称,它仅仅只展示,这在应用运行的时候没有任何影响。

要更改名称,请选择第一个识别器,然后在身份检查器Identity inspector中,将标签Label的值更改为Swipe Left Gesture。对第二个识别器做同样的事情,改变名字为Swipe Right Gesture

他们的名字现在会像这样出现:

现在你已经添加了滑动手势,它们很容易识别,你可以开始使用它们了。添加两个新的视图控制器,并在每个控制器的中心添加一个标签,以在它们重新打开时识别它们。

连接手势

选择向左滑动手势Swipe Left Gesture并打开连接检查器Connections inspector。在Triggered Segues部分,从动作右侧的小圆圈拖动到你想要打开的视图控制器。从弹出窗口中选择Show

对右滑手势Swipe Right Gesture和另一个视图控制器做同样的事情。

编译运行,然后选择手势标签并向左或向右滑动。滑动动作将呈现它们重新连接到的视图控制器。当你向下滑动新场景时,它就会关闭。

改变展现动画

UIKit提供了不同的表现风格和动画,你可以从故事板直接改变你的风格。选择两个新的视图控制器中的任意一个,打开Attributes inspector

过渡样式Transition Style定义了场景在呈现时如何进行动画处理。Presentation设置这个场景显示的方式,不管动画类型是什么。

并不是所有的过渡样式Transition Style动画都能与所有的表示值一起工作。例如,部分曲线不能与iOS 13提供的新表示风格一起工作。要尝试它,你必须将显示Presentation更改为全屏Full Screen

你可以自由地探索它们,并通过简单地从下拉列表中更改一个值来查看可以执行的不同动画。所有这些都不需要任何代码。

总结

在本教程中,我们学习了很多关于故事板的功能,包括:

  • 使用对象库Object Library构建接口并自定义该接口。
  • 通过segue连接屏幕,无需编写任何代码就能让你的应用具有交互性。
  • 自定义视图结构栏Document Outline中的名称和标签。
  • 改变视图控制器之间的过渡动画。

如果想把Storyboard使用的行云流水,需要经常熟练各类控件和约束,Auto Layout的各种概念都得多熟悉,多上手。