来源:http://iaiai.iteye.com/blog/1493956html
Storyboard)是一个可以节省你不少设计手机App界面时间的新特性,下面,为了简明的说明Storyboard的效果,我贴上本教程所完成的Storyboard的截图:
现 在,你就能够清楚的看到这个应用到底是干些什么的,也能够清楚的看到其中的各类关系,这就是Storyboard的强大之处了。若是你要制做一个页面不少 很复杂的App,Storyboard能够帮助你解决写不少重复的跳转方法的麻烦,节省不少时间,以便你可以彻底的专一于核心功能的实现上。
开始
首先启动Xcode,新建一个工程,咱们在这里使用Single View App Template,这个模板会提供一个类和一个Storyboard,免去咱们本身建立的麻烦。
建立完成以后,Xcode的界面大概是这样的:
这 个新的工程由两个类:AppDelegate和ViewController以及一个Storyboard组成(若是你选择了两个设备会有两个 Storyboard),注意这个项目没有xib文件,让咱们首先看看Storyboard是什么样的,双击Storyboard打开他:
Storyboard 的样子和工做方式都和Interface Builder(如下简称为IB)像极了,你能够从左下方的控件库中拖动控件到你的View之中而且组织他们的排放顺序,惟一不一样的地方就 是,Storyboard不止是包含一个视图控件,而是全部的视图控件以及他们之间的关系。
Storyboard对一个视图的官方术语是一个场景,可是一个场景其实就是一个ViewController,在iPhone中一次只可以展现一个场景,而在iPad中一次能够展现多个场景,好比Mail应用程序。
经过尝试添加一些控件,你能够感觉一下Storyboard的工做方式。
这个是数据显示器,显示全部场景及其控件的结构。
在IB中,这个位置显示的是你的NIB文件中的文件,而在Storyboard中这里显示的是ViewController,目前这里只有一个ViewController,咱们接下来可能会增长一些。
这是一个文档管理器的缩小版,叫作dock。
Dock 展现场景中第一级的控件,每一个场景至少有一个ViewController和一个FirstReponder,可是也能够有其余的控件,Dock还用来简 单的链接控件,若是你须要向ViewController传递一个关系时,只须要将其按住Ctrl键拖到ViewController上就能够了。
Note:你大概不会太长使用FirstResponder,由于它只是一个代理控件,表明着当前你所使用的控件。
如今运行这个应用,他会向咱们设计的界面同样。
若是你之前制做过NIB型的应用的话,你也许回去寻找MainWindow.xib ,这个文件包括全部的ViewController,Appdelegate等等,可是在Storyboard中这个特性已经被废止了。
那么,没有这个文件,应用从那里起始呢?
让咱们打开AppDelegate文件,看看那上面是怎么说的: 编程
若是要使用Storyboard特性,那么AppDelegate必须继承自UIResponder类, 以前则是继承自NSObject类的,并且必须有一个不是UIOutlet类的Window属性声明才能够。
如 果你再去看AppDelegate的执行文件,里面大概什么都没有,甚至连 application:didFinishLaunchingWithOptions: 也只是返回了一个 YES,而以前,这里则需声明一个ViewController而且将他设置成起始页面,可是如今这些都没有了。
秘密就在info.plist文件中, 打开Ratings-Info.plist (在 Supporting Files group里) 你就会看到这些:
在 NIB为UI的应用里,info.plist文件中有一个键兼作NSMainNibFile,或者叫作Main nib file base name,他用来指示UIApplication载入MainWindow.xib,而且将他与应用连接起来,而如今这个键值消失了。
而 Storyboard应用则利用 UIMainStoryboardFile,或者 “Main storyboard file base name” 键值来表示当App初始化时的Storyboard名称,当程序运行时,UIApplication会使用 MainStoryboard.sotryboard做为第一加载项,而且将他的UIWindow展现在屏幕上,不须要任何编程工做。
在项目总结面板上,你也能够看到而且编辑这些信息:
若是你还想设置nib文件的话,另外有地方去设置的。
为了完成这个实验性的小程序,咱们打开main.m,加入 小程序
以前是UIApplicationMain()的函数如今是空的, 变成了 NSStringFromClass([AppDelegate class]).
与 以前使用MainWindow.xib的一个最大的不一样是:如今app delegate已经不是Storyboard的一部分了,这是由于app delegate再也不从nib文件中,而侍从Storyboard中加载了,咱们必须告诉 UIApplicationMain 咱们的app delegate类的名字是什么,不然他将没法找到。
制做一个Tab类型的应用
本教程中的Rating App拥有两个Tab,在Storyboard中,很轻松就可以作出一个Tab视图。
回到MainStoryboard.storyboard中,直接从左边的Library拖进来一个TabViewController就能够了。
新 的Tab Bar Controller附带了两个View controller,分别做为Tab的视图使用,UITabBarController被称为包含视图,由于他包含这其余一些View,其余常见的包含 视图还有那vi嘎提鸥鸟 Controller和SplitView Controller。
在iOS 5中,你还能够本身写一个自定义的Controller,这在之前是作不到的。
包含关系在Storyboard中用一下这种箭头表示。
拉一个Label控件到第一个子试图中,命名为“First Tab”,再在第二个子视图中添加一个Label,命名为“Second Tab”。
注意:当屏幕的缩放大于100%时,你没法在单个场景中添加控件。
选中Tab Bar Controller,进入属性检查器,选中“做为起始场景”,以下图:
如今那个没有头的虚虚的小箭头指向了Tab Bar Controller,说明他是起始场景。
这意味着,当你启动这个应用的时候,UIApplication将会将这个场景做为应用的主屏幕。
Storyboard必定要有一个场景是起始场景才行。
如今运行试试吧
code专门为创造这种Tab Bar的应用准备了一个模板,咱们也可使用他,可是本身有能力不用模板本身作一个Tab Bar也是不错的事。
若是你添加了多于五个子视图到一个TabBarcontroller的话,并不会创造五个Tab,第四个tab会自动变成More标签,不错吧
制做一个表格视图
目前链接到Tab bar Controller的视图都是普通的View Controller,如今,我要用一个TableViewController来代替其中的一个ViewController。
单击第一个视图并删除,从Library中拖出一个TableViewController。
在选中这个TableViewController的前提下,从Library中拖出一个NavController,将会直接附着在上面。
固然也能够调换顺序,我彻底没意见。
因为NavController和TabBarController同样也是一个包含控制器视图,因此他也必须包含另外一个视图,你能够看到一样的箭头链接者这两个View。
请注意全部嵌套在NavController下的View都会有一个Navigation Bar,你没法移除它,由于他是一个虚拟的Bar。
若是你检视属性检测器,你就会发现全部bar的属性都在一块儿:
“Inferred”是Storyboard中的默认设置,他意味着继承的关系,可是你也能够改变他。可是请注意这些设置都是为了让你更好的进行设计和这样设置的,随意修改默认设置会带来不可碰见的后果,施主自重。
如今让咱们把这个新的场景链接到Tab Bar Controller中,按住Ctrl拖动,或者右键。
当你放手的时候,一个提示框会出现。
固然是选第一个了,Relationship – viewControllers ,这将自动建立两个场景之间的关系。
直接拖动就能够改变Tab Item的顺序,同时也会改变显示Tab的顺序,放在最左边的Tab会第一个显示。
如今运行试试看吧
在咱们在这个应用中加入任何实质性的功能以前,咱们先来清理一下Storyboard,你不须要改变TabBarController中的任何内容而只须要改变他的子视图就能够了。
每当你链接一个新的视图到TabBarController中的时候,他就会自动增长一个Tab Item,你可使用他的子视图来修改该Item的图片和名称。
在NavController中选中Tab Item而且在属性编辑其中将其修改成Player。
将第二个Tab Item命名为“Gesture”
咱们接下来把自定义的图片加入到这些item中, 源码 中包含一个名为“Image”的文件夹,在那里你能够找到咱们用到的资源。
接下来,将NavController的title改成Player,也可使用代码··
运行看一看,难以置信吧,你到如今也没写一条代码。
原型表格单元
你也许已经注意到了,自从咱们加入了Table View Controller以后,Xcode便会现实下面这样一条警告。
这条警告是:“Unsupported Configuration: Prototype table cells must have reuse identifiers”意思是,原型表格单元必须有一个身份证(意译啦)
原 型单元格是另外一个Storyboard的好特性之一。在以前,若是你想要自定义一个Table Cell,那么你就不得不用代码来实现,要么就要单首创建一个Nib文件来表示单元格内容,如今你也能够这样作,不过原型单元格能够帮你把这一过程大大的 简化,你如今能够直接在Storyboard设计器中完成这一过程。
Table View如今默认的会带有一个空白的原型单元格,选中他,在属性控制器中将他的Style改成subtitle,这样的话,每一格就会有两行字。
将附件设置为Disclosure Indicator而且将这个原型单元格的Reuse Identifier 设置喂“PlayerCell”,这将会解决Xcode所警告的问题。
试着运行一个,发现什么都没变,这并不奇怪,由于咱们尚未给这个表格设置一个数据来源(DataSource),用以显示。
新建一个文件,使用UIViewContoller模板,命名为 PlayersViewController ,设置喂UITableViewController的子类,不要勾选创建XIB文件。
回到Storyboard编辑器,选择Table View Controller,在身份控制器中,把他的类设置为PlayerViewController,这对于把Storyboard中的场景和你自定义的子类挂钩是十分重要的。要是不这么作,你的子类根本没用。
如今起,当你运行这个应用时,table view controller实际上是PlayersViewContoller的一个实例。
在 PlayersViewController.h 中声明一个MutableArray(可变数组) 数组
这个数组将会包含咱们的应用的主要数据模型。咱们如今加一些东西到这个数组之中,新建一个使用Obj-c模板的文件,命名为player,设置喂NSObject的子类,这将会做为数组的数据容器。
编写Player.h以下: app
编写Player.m以下: 框架
这里没有什么复杂的,Player类只是一个容器罢了,包含三个内容:选手的名字、项目和他的评级。
接下来咱们在App Delegate中声明数组和一些Player对象,并把他们分配给PlayerViewController的players属性。
在AppDelegate.m中,分别引入(import)Player和PlayerViewController这两个类,以后新增一个名叫players的可变数组。 编辑器
修改didFinishLaunchingWithOptions方法以下: ide
这将会创造一些Player对象并把他们加到数组中去。以后在加入: 函数
咦,这是什么?目前的状况是:咱们但愿可以将players数组链接到PlayersViewController的players属性之中以便 让这个VC可以用作数据来源。可是app delegate根本不了解PlayerViewController到底是什么,他将须要在storyboard中寻找它。
这是一个 我不是很喜欢storyboard特性,在IB中,你在MainWindow.xib中老是会有一个指向App delegate的选项,在那里你能够在顶级的ViewController中向Appdelegate设置输出口,可是在Storyboard中目前这 还不可能,目前只能经过代码来作这样的事情。 工具
咱们知道storyboard的起始场景是Tab Bar Controller,因此咱们能够直接到这个场景的第一个子场景来设置数据源。
PlayersViewController 在一个NavController的框架之中,因此咱们先看一看UINavigationController类:
而后询问它的根试图控制器,哪个是咱们要找的PlayersViewController:
可是,UIViewController根本就没有一个rootViewController属性,因此咱们不能把数组加入进去,他又一个topViewController可是指向最上层的视图,与咱们这里的意图没有关系。
如今咱们有了一个装在了players物体合集的数组,咱们继续为PlayersViewController设置数据源。
打开PlayersViewController.m,加入如下数据源方法:
真正起做用的代码在cellForRowAtIndexPath方法里,默认的模板是以下这样的:
无疑这就是之前设置一个表格视图的方法,不过如今已经革新了,把这些代码修改以下:
这看上去简单多了,为了新建单元格,你只需使用以下代码:
若是没有现存的单元格能够回收,程序会自动创造一个原型单元格的复制品以后返回给你,你只须要提供你以前在Storyboard编辑视图中设置的身份证就能够的,在这里就是“PlayerCell”,若是不设置这个,这个程序就没法工做。
因为这个类对于Player容器目前一无所知,因此咱们须要在文件的开头加入一个引入来源
记得要建立synthesize语句哦亲
如今运行应用,会看到Table里有着players容器。
请注意:咱们这里只使用一种单元格原型,若是你须要使用不一样类型的单元格的话,只须要在storyboard中另外加入一个单元格原型就能够了,不过不要忘记给他们指派不一样的身份证。
设计自定义的原型单元格
对于不少应用来讲,使用默认的单元格风格就OK了,可是我恰恰要在每个单元格的右边加上一个一个图片来表示选手的评级,可是添加图片对于默认类型的单元格来讲并不支持,咱们须要自定义一个设计。
让咱们转回MainStoryboard.storyboard,选中table view中的prototype cell,把它的Style attribute改成Custom,全部默认的标签都会消失。
首先把单元格变得更高一些,你能够直接拉它,也能够在大小控制器中修改数字,我在这里使用55点的高度。
从 Objects Library中拖出两个标签物体,按照以前的样式安插到单元格里,记得设置label的Highlighted颜色为白色,那样的话当单元格被选中的时候会看起来更好看一些。
以后添加一个Image View对象,将它放置在单元格的右边,设置他的宽度为81点,高度并不重要,在属性检查器中设置模式为置中。
我把标签设置为210点长以确保他不会和ImageView重合,最后总体的设计会看起来象下面这样:
因为这是一个自定义的单元格,因此咱们不可以使用UITableView默认的textLabel和detailLabel来设置数据,这些属性也再也不指向咱们的单元格了,咱们使用标签(tags)来指定标签。
将Name标签的tag设置为100,Game的设置喂101,image的设置喂102,在属性检查器里设置哦亲。
以后打开 PlayersViewController.m ,在PlayersViewcontroller中将cellForRowatIndexPath修改成:
这里是用了一个新的方法,叫作ImageRating,在 cellForRowAtIndexPath方法以前加入这个方法:
这就完成了,运行看看:
这 和咱们想象的结果并非很符合,咱们修改了原型单元格的属性和高度,可是table view却没有考虑进去,有两种方法能够修复它,咱们能够改变table view的行高或者加入 heightForRowAtIndexPath 方法来修改,地一种方法更简单,咱们就用他。
注意:在一下两种状况下,你应该使用 heightForRowAtIndexPath 方法:一是,你不能预先知道你的单元格的高度,二是不一样的单元格会有不一样的高度。
回到MainStoryboard.storyboard,在大小检查器中将高度设置为55:
经过这种方式的话,若是以前你是使用拖动而不是键入数值的方式改变高度的属性的话,则table view的数值也会自动改变。
如今运行看看,好多了吧
为原型单元格设置子类
咱们的表格视图已经至关像模像样了,可是我并非很喜欢使用tag来访问label,要是咱们可以把这些lable链接到输出口,以后在回应属性中使用他们,该多好,并且不出所料,咱们能够这样作。
使用 Objective-C class模板新建一个文件,命名为PlayerCell,继承UITableViewCell。
修改PlayerCell.h
修改PlayerCell.m
这个类自己并不其很大的做用,只是为nameLabel、gameLabel和ratingImageView声明了属性。
回 到MainStoryboard.storyboard选中原型单元格,将他的class属性修改成“PlayerCell”,如今当你向table view请求dequeueReusableCellWithIdentifier,他会返回一个PlayerCell实例而不是一个普通的 UITableViewCell实例。
请注意我将这个类和reuse Indetifier的名字命名的同样,只是营卫我喜欢这样哦亲,这两个之间其实没啥关系。
如今你能够将标签和image view链接到输出口去了,选中或者将他从连接检查器拖动到table view cell。
请注意:要把这个control链接到table view cell而不是view controller哦亲,别选错了。
如今咱们把一切都连接好了,只须要加入数据源的代码就能够了。
咱们如今将接收到 dequeueReusableCellWithIdentifier 的控件指派到PlayerCell,只须要简单的使用已经连接labels和image view到设置好的属性上就能够了,这会让这个设计看上去更加好控制,更加简明。
固然,在PlayerCell前要引入资源:
试着运行,你会发现其实什么都没有变化,但是咱们都知道,内部已经有了变化。
在这相同的场景下面,咱们但是在使用子类呢。
这里还有一些设计小窍门:第一点:必定要设置标签被选中时的颜色。
第二点,确保你加入单元格的字符大小是能够变化的,这样,当单元格大小变化时,他的内容的大小也会跟着变化,好比说:
在PlayersViewController.m中加入以下方法:
这个方法加入好了以后,用手指轻扫一行单元格,会出现一个删除键,试试看
Delete按钮出如今右边,遮住了一部分评级图片,怎么解决呢?
打开MainStoryBoard.storyboard,选中table view cell中的image view,在大小检查器中修改Autosizing属性,是它可以跟随上级view的边缘。
为labels设置一样的属性。
加入了这些变更以后,删除按钮如咱们意料的出现了:
其实,最好的作法是让这些星星在出现delete按钮的时候消失,不过这只是一个练习,不要太较真哦亲