该教程是基于你在前面的课程中构建的项目上进行的。学完本教程后,你将使用你前面学到的视图、视图控制器、动作、导航的内容,还会为应用创建一些关键的用户界面,并在场景中添加行为
以下就是本节课的内容:
1. 使用storyboard来定义应用内容和流程
2. 管理多个视图控制器
3. 在用户界面上,给元素添加动作
完成本节教程后,你的应用应该如下所示:
创建第二个场景
到现在为止,你所操作的只是一个由视图控制器管理的单场景,它就是一个可以把事件添加到待办事件列表的页面,即添加事件的场景。现在,是时候创建列表了。幸运的是,IOS已经内置了一个功能强大的类:table view(UITableView),该类用于显示可以滚动的列表项。
在storyboard的场景中添加表格的步骤:
1. 在项目导航器中,选择Main.storyboard。如果项目导航器被关闭了,点击Xcode toolbar上的Navigator按钮就可以打开它:
如果助手编辑器是打开的,那么点击Standard按钮就可以关闭它。
2. 在utility区域打开对象库。
3. 在对象库的搜索框中,输入table view controller,快速找到该对象。
4. 从列表中把一个Table View Controller对象拖动到画布上。如果有需要,你可以使用菜单:Editor > Canvas > Zoom,对场景进行缩小。如果当你试图把一个table view拖动到画布上来,但是没有拖动成功时,你很有可能拖动的是table view,而不是table view controller。
现在,storyboard中已经有两个场景了,一个用于显示待办列表,一个用于添加待办事项:
当用户打开应用时,应该先看到待办列表,因此,你可以把table view controller设置为开始场景,具体的做法是:
把添加事件场景前的入口点拖动放到待办列表的场景前。
现在,table view controller被设置为初始的视图控制器了,它作为应用启动后加载的第一个场景。
注意:现在你运行项目,你看到的应该是一个空的table view——即页面被水平线分隔为一行一行,但是每一行上没有任何内容。
在table view中显示静态的内容
因为你还没有学习数据的存储,因此,现在创建和存储要在列表上显示的数据还为时过早。但是,你的界面上也是不非得需要真实的数据。Xcode中,你可以给Interface Builder中的table view创建一些静态的内容。这样的方式去看界面长什么样子,就简单省事多啦,你还可以使用这种办法来尝试更多的想法哦。
在table view中创建静态单元格:
1. 如果有需要,打开outline view
2. 在outline view中,选择位于Table view controller下方的Table view
3. 选中table view,打开utility区域的Attributes inspector
4. 在Attributes inspector中,在Content option的弹出菜单中,选择 Static Cells。在storyboard中的table view中会出现空的三个表格单元格
5. 在outline view中,选择最上面的单元格
6. 在Attributes inspector中,在Style option弹出的菜单中,选择Basic。Basic样式中,包含了一个label,因此,Xcode会在单元格中创建一个label,label上的文字是Title。
7. 选择outline view中的label:
8. 在Attributes inspector中,把label的文本修改为“修剪草坪”。输入完成后,按下return键或在utility区域单击就可以看到效果。
9. 或者,你也可以在label控件上双击对文本进行修改。
10. 给其它两个单元格重复上述4~7步,输入其它的待办事项。
11. 创建足够多的单元格(多于一页),创建的方式可以使用复制、粘贴,也可以拖动。
检查点:运行应用。你会看见你在Interface Builder中添加的东东,因为表格里的内容已经超过一屏了,你可以来回滚动感觉下。在模拟器的屏幕上,你会发现表格里的内容仍然正常显示。使用table view,默认会有很多的行为。你肯定注意到了:最上面的单元格已经盖住了设备的状态栏——也就是显示时间、电量和手机其它信息的区域。这是个问题,不过不用担心,后面教程中会修复的。
添加segue来向前导航
是时候给table view添加导航了,添加导航后,用户可以从列表页面跳转到上节教程中制作的添加待办事项的页面。我们在Defining the Interaction(定义交互)章节中已经讲过,两个场景之间的转换被称作segue。
在创建segue之前,需要对场景进行一番配置。首先,把table view controller包裹在navigation controller中。还记得Defining the Interaction(定义交互)章节讲到的内容吗?navigation controller会提供一个导航条,并保存了对导航栈的跟踪。接下来,将在导航条上添加一个按钮,用于跳转到添加待办事项的场景。
在table view controller中添加navigation controller需要以下几个步骤:
1. 在outline view中,选中Table view controller
2. 选中table view controller,选择菜单:Editor > Embed In > Navigation Controller
进行完上述操作后,Xcode就会给storyboard中添加一个新的navigation controller,给它设置storyboard的入口点,在新的navigation controller和已经存在的table view controller之间创建一个关系。
在画布中,如果你选中连接两个场景的图标,你就会在outline view下方的navigation controller中看到relatioinship root view controller to table view controller的字样。这就意味着显示在导航条下的内容视图将是table view。storyboard的入口点被设置给了navigation controller,这是因为应用中所有显示的内容,都在navigation controller里。navigation controller既是待办列表场景的容器,又是添加待办事项场景的容器。
检查点:运行应用。在table view的上面,你会看到一块额外的空间,它就是由navigation controller提供的导航条。导航条把它的背影扩展到了顶部的状态栏上了,因此,状态栏不会再遮盖你的内容了。
接下来,要在导航条上添加一个待办列表的标题和一个添加待办的按钮。导航条从navigation controller中显示的视图控制器中获取标题——导航条自己是没有标题的。因此,你给待办列表的导航项(table view controller)添加标题,而不是直接给导航条添加标题。
添加标题的步骤如下:
1. 在outline view或在画布上,选中table view controller下的navigatioin item:
2. 在attributes inspector的Title字段中,键入待办列表,然后单击return键。这时,Xcode会自动把该场景的描述由Table View Controller改变为待办列表,这样,你就更加方便去定位这个场景了。在outline view中显示的描述如下:
3. 在对象库中,找到Bar Button Item对象。
4. 拖动一个Bar Buttom Item对象,把它放置到table view controller中导航条的右边,这样,文字为Item的按钮就出面在导航条上了。
5. 在outline view或在画布上,选中bar button item。
6. 在attributes inspector中,在Bar Button Item节中找到Identifier选项,从它的弹出菜单中选择Add菜单。这时,按钮的样子就变为Add按钮了(+)。
检查点:运行应用。这时,导航条应该有一个标题,并显示添加按钮。但是,点击按钮是没有任何反应的。
使用添加按钮的意图是引出添加待办事项的场景。该场景已经在前面的教程中创建了,但是它还没有连接到其它的场景上。你需要配置添加按钮,使得当用户按下按钮时,页面可以跳转到添加待办事项的页面。为了实现上述效果,你应该这样做:
1. 在画布上,选中添加按钮
2. 按住Control,从按钮上一直拖动到添加待办事项的视图控制器
在拖动结束的位置,会出现一个快捷菜单:
Action Segue菜单可以让你选择:当用户点击添加待办事项按钮时,你需要使用哪种类型的segue,来从待办列表过渡到添加待办事项页面。
3. 从Action Segue菜单中,选择show
Xcode配置segue,设置在navigation controller中显示添加待办事项的视图控制器,在Interface Builder中,你将会看到导航条
检查点:运行应用。点击添加按钮,页面就会从table view视图控制器导航到添加待办事项视图控制器。因为你使用了带有show segue的navigation controller,因此,系统为你把返回导航的操作给处理了。这就意味着如果你点击返回按钮,页面就会回到列表页面。
你通过使用show segue得到的push-style类型的导航的效果与你想象的有所不同。push navigation被设计为向下攥取的界面,在该界面上,你可以提供有关用户选择东东的更多信息。再者,添加操作一般是一个模态的操作——用户执行完整、独立的动作,然后从这个场景返回到主导航。这种类型场景恰当的展现方法应该是modal segue。
不要删除已经存在的segue,也不要创建一个新的segue,把segue的类型改为modal就可以了。与storyboard中大多数可选的元素一样,你可以在Attributes inspector面板中添加segue的属性。
改变segue类型:
1. 在outline view或在画布上,选择从table view controller到添加待办事项的view controller的segue。
2. 在Attributes inspector中,在segue选项的弹出菜单中,选择Present Modally。
因为模态的视图控制器,没有被添加到导航栈中,因此,它不会从table view controller的navigation controller中获得导航条。但是,你可能会想在模态的视图控制器上也显示导航条,这样,会给用户一个统一的视觉效果,你可以这样做:当模态出现时,给添加待办事项的视图控制器添加一个导航条,把它嵌在自己的navigation controller中:
给添加待办事项视图控制器添加导航控制器的做法:
1. 在outline view中,选中View Controller
2. 选择Editor > Embed In > Navigation Controller
与前面讲过的一样,Xcode添加了一个导航控制器,并在view controller的最上面显示导航条。下面,给这个导航条配置一个标题和两个按钮:取消、保存。随后,再给这两个按钮添加事件。
配置添加待办事项视图控制器的导航条:
1. 在outline view或在画布上,选中view controller下的navigation item
2. 在Attributes inspector的title字段里,键入添加待办事项文字。Xcode会自动把视图控制器场景的描述改变为添加待办事项场景,这样会让你定位起来更加方便,如下图所示:
3. 从对象库中拖动一个Bar Button Item对象,把它放在添加待办事项视图控制器的右边
4. 在Attributes inspector的Identifier选项中,从弹出菜单里选择Save,这时,按钮上的文本就变为Save
5. 再从对象库中拖动一个Bar Button Item对象,把它放在添加待办事项视图控制器的左边
6. 在Attributes inspector的Identifier选项中,从弹出菜单里选择Cancel,这时,按钮上的文本就变为Cancel
检查点:运行应用。单击新增按钮。你所看到的仍然是添加待办事项场景,但是,该场景不再是导航条上有返回按钮的场景了,相反,你会看到你刚刚添加的两个按钮:Save和Cancel。现在,这两个按钮还没有链接到任何的动作上,因此你点击按钮时不会有任何的反应。接下来的任务就是:给这两个按钮配置完成或取消新增待办事项的编辑,并且返回到待办列表。
创建自定义的视图控制器
到目前为止,一行代码都没有写,就已经完成了所有的配置。要完成添加待办事项视图控制器的配置,需要写一些代码,还要找个地方存放这些代码。
项目创建成功后,响应添加待办事项视图控制器的代码就生成了,是在ViewController.h和ViewController.m文件中。这两个文件是自定义的视图控制器,作为Single View Application模板的一部分,在项目创建的同时一同被创建。但是,学习如何自己动手创建和配置视图控制器是非常重要的,因为这是IOS应用开发的常用功能。所以,现在需要创建一个名为AddToDoItemViewController的视图控制器,用于响应stroyboard中的添加待办事项的场景。AddToDoItemViewController是ViewController的子类,因此,在它里面可以获取到视图控制器所有的基本功能。
如果你愿意的话,你甚至可以删除ViewController.h和ViewController.m文件,这是因为在这个教程中,它们根本没有作用。删除的方法是:在项目导航器中,选择要删除的文件,按下Delete键,在出现的对话框中,点击Move to Trash选项。
创建自定义的视图控制器:
1. 选择菜单:File > New > File,或者使用Command + N快捷键
2. 在弹出的对话框的左边,在IOS节中选择Source
3. 选择Cocoa Touch Class,单击下一步
4. 在Class字段内,输入AddToDoItem
5. 在Subclass的弹出菜单中,选择UIViewController,类的标题就变成AddToDoItemViewController了,Xcode这样命名的目的是为了看得更清楚一些。
6. 确保Also create XIB file选项没有被勾选
7. 确保Language选项选择的是Objective-C
8. 点击Next按钮。文件默认的存储位置是在项目的目录中。Group选项默认是应用的名称。
9. 保持其它选项的值为默认值,点击Create。
完成上述步骤后,Xcode就创建了两个文件:AddToDoItemViewController.h(接口文件)和AddToDoItemViewController.m(实现文件)文件。
这样,你就已经创建了自定义的视图控制器了,还有一步很重要,你得告诉storyboard去使用这个视图控制器:你得把添加待办事项场景由原来使用的ViewController换为AddToDoItemViewController。
更换的方法:
1. 在项目导航器中,选中Main.storyboard
2. 如果需要,请打开outline view
3. 在outline view中,在添加待办事项场景下,选中View Controller
4. 在utility区域,单击第三个图标,打开Identity inspector
indentity inspector可以让你编辑storyboard中,与对象的identity相关的对象的属性,例如对象属于哪个类。
5. 打开Class选项的弹出菜单,弹出菜单中的内容是所有Xcode可以识别的视图控制器的列表。列表中的第一个元素应该就是你自定义的视图控制器:AddToDoItemViewController
6. 为该场景选择使用AddToDoItemViewController
注意:在outline view中,Xcode改变了添加待办事项视图控制器的描述,从View Controller变为添加待办事项。Xcode的这种作法使得自定义的类更容易被理解。
在运行时,故事板会创建AddToDoItemViewController类的实例,即自定义视图控制器的子类。应用中添加待办事项的场景将获取storyboard中定义的界面和定义在AddToDoItemViewController.m中的行为。
现在可以在故事板中创建一个响应待办列表场景的自定义类了。因为,待办列表场景是一个table view controller,因此,它的类是UITableViewController类的子类。同样,UITableViewController也提供了视图控制器的基本行为,还有一些只能被table view使用的行为。
创建UITableViewController的子类:
1. 选择菜单:File > New > File,或者使用Command + N快捷键
2. 在左边IOS节下的Source中,选择Cocoa Touch Class
3. 单击Next
4. 在Class字段中,输入ToDoList
5. 在Subclass of的弹出菜单中,选择UITableViewController,类的标题就变为ToDoListTableViewController了
6. 确保Also create XIB file选项没有被勾选
7. 确保Language选项选择的是Objective-C
8. 点击Next按钮。文件默认的存储位置是在项目的目录中。Group选项默认是应用的名称。
9. 保持其它选项的值为默认值,点击Create。
完成上述步骤后,Xcode就创建了两个文件:ToDoListViewController.h(接口文件)和ToDoListViewController.m(实现文件)文件。
为待办列表场景配置Identity:ToDoListViewController:
1. 在项目导航器中,选择Main.storyboard
2. 在outline view中,选择待办列表场景下的Table view controller,然后打开utility区域的Identity inspector面板
3. 从Class选项的弹出菜单中,选择ToDoListViewController
好了,可以给你自己的视图控制器添加代码了。
给返回的导航添Unwind Segue
除了show和modal类型的segue,Xcode还提供了unwind类型的segue。该类型的segue,可以让用户从指定的场景返回到前一个场景,并且,当用户返回到前一场景时,该类型的segue还为自己编写的代码提供了执行的地方。我们要从AddToDoItemViewController返回到ToDoListViewController,就需要使用该类型的segue。
要创建unwind类型的segue,首先,需要给目标视图控制器(即将要被展现的场景所使用的视图控制器)添加一个方法,该方法的类型必须是IBAcion,参数类型为UIStoryboardSegue。因为你想返回到待办列表场景,因此,你需要按照上述的要求在ToDoListViewController的接口和实现文件中添加方法。
添加方法的步骤:
1. 在项目导航器中,打开ToDoListViewController.h文件
2. 在@interface的下方,添加下面的代码:
- (IBAction)unwindToList:(UIStoryboardSegue *)segue;
3. 在项目导航器中,打开ToDoListViewController.m文件
4. 在@implementation下方,添加下面的代码:
- (IBAction)unwindToList:(UIStoryboardSegue *)segue {
}
你可以把方法的名称命名为你喜欢的任意有效的名称。示例中的方法名是:unwindToList,这样命名的原因是为了从方法的名称上就可以看出方法的作用。在后面的项目中,都会采用类似的命名约定。
现在,这个方法的实现体是空的。随后,这个方法将被用于从AddToDoItemViewController中检索数据,然后把检索到的数据添加到待办列表中。
要创建unwind segue,并把它链接到Cancel和Save按钮上。
具体的做法是:
1. 在项目导航器中,选中Main.storyboard
2. 在画布上,按钮Control键,从Cancel按钮上一直拖动到画布顶部最右边的Exit按钮上:
如果你在画布的最上边没有找到Exit按钮,而是找到了画布的描述,那你就不停的使用Editor > Canvas > Zoom菜单,直到你能看见为止。
在拖动结束的地方,会出现一个菜单:
3. 从快捷菜单中,选择unwindToList。
4. 这就是你刚刚添加到ToDoListTableViewController.m文件里的动作。现在,如果用户点击Cancel按钮,那么,应该就会回到待办列表页面。这时,unwindToList方法被调用。
5. 在画布上,按住Control键,从Save按钮拖动到Exit按钮。
在拖动结束的地方,会出现一个菜单:
6. 在快捷菜单中,选择unwindToList
现在,当用户点击Save按钮时,页面就会跳转到待办列表场景,同时,unwindToList方法被调用。
注意:Save和Cancel两个按钮使用了同样的动作。在后面的教程中,将写代码来区分这两种不同的情况。
检查点:运行应用。刚启动完成,你会看见一个table view——但是里面没有数据。单击添加按钮,应用就会从待办列表页面跳转到添加待办事项页面。你可以点击添加待办事项页面的Save按钮或Cancel按钮,回到列表页面。
数据为什么不显示了?table view有两种获取数据的方式——静态、动态。如果table view的视图控制器已经实现了必须的方法:UITableViewDataSource,那么,table view数据来源就是视图控制器,而不管在Interface Builder中是否配置了静态数据。现在打开ToDoListTableViewController.m文件,你会在发现文件里已经实现了三个方法——numberOfSectionsInTableView,tableView:numberOfRowsInSection,tableView:cellForRowIndexPath。在后面的教程中,将使用这三个方法来显示动态数据。
回顾
到现在为止,你已经完成了应用界面的开发。应用一共有两个场景——待办列表,添加待办事项,用户还可以在这两个页面之间来回导航。下一个模块,就要实现添加待办事项、浏览待办列表的能力。