前言:因为手头各种讲解iOS的教程里都在讲Interface Builder,而新的Xcode里已经开始使用更整合的Storyboard机制,然后找到了这个教程——Beginning Storyboards in iOS 5 Part 1,很长~目前翻译的只是第一部分~而且因为完全没有代码语言基础总觉得有很多翻译不妥~权当熟悉了,sigh~
原作者注:本文是iOS 5 Feast中的第二个教程,这个教程是我们的新书《iOS 5 By Tutorials》中的一个免费预览的章节,该段内容作者是Matthijs Hollemans, 他以前还写过另一本书《iOS Apprentice Series》。Enjoy!
Storyboarding 是iOS5里一个让人振奋的新功能,利用它你可以快速构建你的应用界面并节省大量的时间。为了更好的阐述这是一个什么东西,我会用一张图来说明。下面这个截图就是我们在这个教程中将要完成的storyboard
也许你还不清楚这个应用到底是用来干嘛的,但是你可以很清楚的看到这个应用都有那些不同的界面并且这些界面之间是如何相互联系起来的,这就是storyboards的作用。
如果你的应用有很多不同的界面,那么利用storyboard可以帮助你轻松的建立不同界面之间的联系,让你不用再写大量的代码用来进行界面之间的跳转,从而节约大量的时间和精力,并且你不再需要为应用的每个视图控制器建立独立的nib文件,一个storyboard包含了所有的视图控制器以及相互之间关系设计。
Storyboard比起nib文件有以下优点:
-
利用storyboard可以更方便地宏观查看你应用中所有地界面视图,并且更便于梳理其中的关系,这一切都可以在一个文件中完成,而不用展开一堆nib文件* storyboard可以很方便地描述不同界面之间联系,这些联系叫作“segues”,你可以利用“ctrl+拖拽”地方式创建一个视图到另一个视图地联系,幸亏有了这个你可以少写一些代码来维护你的UI
-
在Storyboard里利用新的原型组件和静态组件可以更简单地制作表视图,你几乎可以在视图编辑器里根据自己地要求完全重新设计表视图,这些都可以大幅度减少你编写代码地时间
当然凡事总不能完美,storyboard也有一些制约,storyboard地编辑器比起Interface Builder还有一些不足,有一些事情是IB可以实现而storyboard还无法完成的,你还需要一个监视器,尤其是在写iPad应用的时候。
如果你属于那种讨厌Inerface Builder并且只愿意通过代码来实现界面的人,那么storyboard也许不太适合你。就个人而言,我更愿意尽可能的少写代码——尤其是UI代码!——所以这个工具于我而言十分有用。
你在iOS5和Xcode 4.2里依然可以继续使用nib文件。有了storyboard并不意味着就要立刻抛弃雕Interface Builder,如果你选择继续使用nib文件那就坚持到底吧,不过你应该同时尝试把nib和storyboard联合使用,这个问题并不是非此即彼的。
在这个教程里我们将会看到你可以利用storyboard做哪些事情,我们即将编写的这个应用并没有什么具体的功能但是它可以让你了解到storyboard里你最常使用的一些功能是如何工作的。
初识
打开Xcode并创建一个新的工程。在这里我们选择一个Single View Application的模板来开始创建我们的应用
按照以下格式填写:
* Product Name: Ratings(其实随便写也可以啦)
* Company Identifier: 公司信息,域名相关也可以
* Class Prefix: 空着不用填
* Device Family: iPhone
* Use Storyboard: 勾选
* Use Automatic Reference Counting: 勾选
* Include Unit Tests: 这个不用选
然后Xcode就会创建一个工程,主界面大致如下:
我们的工程默认包含两个类,分别是“Appdelegate”和“ViewController”,还有本篇教程的重点:MainStoryboard.storyboard文件。你会发现工程里没有任何的.xib文件,甚至没有MainWindow.xib
我们先来看一下storyboard吧,点击MainStoryboard.storyboard文件后工程的导航视图里会显示Storyboard的编辑器
Storyboard的编辑器的式样和使用方法跟Interface Builder十分相似。你可以直接从组件库(右下角)中将组件拖拽到视图控制器里来设计式样,区别在于storyboard包含了你应用中的所有视图界面,而Interface Builder只能一个一个进行设计。
Storyboard的官方术语叫作“scene”,但一个scene其实并不比一个视图控制器多出什么功能。在以前你会针对每个scene/视图控制器创建独立的nib文件,而现在他们全部都被一个storyboard联系了起来。
在iPhone视图中你一次只能看见一个scene界面,而采用iPad视图时则可以一次显示多个,比如同时显示分栏的控制面板和详情面板,或者是弹出窗口的内容。
为了更好的感受以下编辑器是如何工作的,我们拖拽几个控件到空白的视图控制器中:
左侧边栏中显示的是树状的文件结构:
在Interface Builder中这个区域只会列出当前nib文件中包含的控件,而在Storyboard编辑器中会显示出你所有视图控制器中的内容。尽管目前我们这个storyboard中还只有一个视图控制器,但是在后面我们还将路续添加一些新的界面。
在每个scene下方还有一个小型的文件结构视图,这个叫作Dock:
在Dock上会显示出当前scene中最高层级的那些组件,每个scene最少包含一个First Responder(响应)组件和一个View Controller(视图控制器)组件,但其中也可以包含更多其他的组件,这些稍后会详细解说。Dock十分便于创建关联性,如果你需要把一些东西跟这个视图联系起来,只需要把响应的图标拉倒Dock上就可以了。
运行这个应用你会发现它完全跟在编辑器里设计的一模一样:
如果你以前曾经开发过基于nib文件的应用那么在这个工程里就会一直有一个MainWindow.xib文件,这个nib文件包含了最高层级的UI控件和一个或多个视图控制器,而当你把应用的UI都放进一个storyboard以后,这个MainWindow.xib就再也派不上用场了
那么应用是如何在没有ManWindow.xib文件的情况下正确读取storyboard的呢?
我们可以看一下应用的delegate类,打开Appdelegate.h文件你会看到下面的内容
import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property(strong, nonatomic) UIWindow *window;
@end
我们可以看到,要想在应用中使用storyboard必须从UIResponder继承相关属性(以前是继承自NSObject)并且确保其具有UIWindow属性(不像以前,这不再是一个单纯的IBOutlet)。
如果你查看AppDelegate.m文件,你会看到它其实什么都没干,几乎所有的方法都是空的。而在以前这里起码会添加一个主视图控制器来显示窗口的rootViewController(根视图控制器)属性,但是现在什么都没有了。
所有的秘密都在Info.plist文件里。点击Ratings-Info.plist(它在Supporting Files组内)你会看到下面这段:
基于nib文件的工程你会在Info.plist中找到一个NSMainNibFile的项,也可能显示为“Main nib file base name”,这个值会指引UIApplication载入MainWindow.xib文件,而我们的Info.plist中不再有这个项了,取而代之的是一个名为UIMainStoryboardFile或者“Main storyboard file base name”的项,当应用启动时这个被指定的storyboard文件必须加载,当该配置存在时,UIApplication会载入MainStoryboard.storyboard文件并自动从storyboard中实例化第一个视图控制器并将它显示在一个新的UIWindow空间中,完全不需要写任何一行代码。
你可以参考下图的设置界面
这儿会有一个选项让你选择要用storyboard还是nib文件来开始iPhone/iPad应用的开发
让我们再看一下main.m文件,以此作为本部分的结尾
import <UIKit/UIKit.h>
import "AppDelegate.h"
int main(int argc, char*argv[]){
@autoreleasepool {return UIApplicationMain(argc, argv, nil,
NSStringFromClass([AppDelegate class]));
}}
在以前,UIApplicationMain()的变量是空值,而现在则变成了NSStringFromClass([AppDelegate class])
其中最大的区别就是应用的delegate类不再从nib文件载入(跟storyboard也没关系),我们必须告知应用的UIApplicationMain具体的delegate类的名称,否则无法正常运行