故事版(Storyboard)是一个能够节省你很多设计手机App界面时间的新特性,下面,为了简明的说明Storyboard的效果,我贴上本教程所完成的Storyboard的截图:


The full storyboard we'll be making in this tutorial.

现在,你就可以清楚的看到这个应用究竟是干些什么的,也可以清楚的看到其中的各种关系,这就是Storyboard的强大之处了。如果你要制作一个页面很多很复杂的App,Storyboard可以帮助你解决写很多重复的跳转方法的麻烦,节省很多时间,以便你能够完全的专注于核心功能的实现上。

 

开始

 

首先启动Xcode,新建一个工程,我们在这里使用Single View App Template,这个模板会提供一个类和一个Storyboard,免去我们自己创建的麻烦。

Xcode template options

 

 

创建完成之后,Xcode的界面大概是这样的:

 

Xcode window after creating project

 

 

这个新的工程由两个类:AppDelegate和ViewController以及一个Storyboard组成(如果你选择了两个设备会有两个Storyboard),注意这个项目没有xib文件,让我们首先看看Storyboard是什么样的,双击Storyboard打开他:

 

Storyboard editor

 

 

Storyboard的样子和工作方式都和Interface Builder(以下简称为IB)像极了,你可以从左下方的控件库中拖动控件到你的View之中并且组织他们的排放顺序,唯一不同的地方就是,Storyboard不止是包含一个视图控件,而是所有的视图控件以及他们之间的关系。

 

 

 

Storyboard对一个视图的官方术语是一个场景,但是一个场景其实就是一个ViewController,在iPhone中一次只能够展示一个场景,而在iPad中一次可以展示多个场景,比如Mail应用程序。

通过尝试添加一些控件,你可以感受一下Storyboard的工作方式。

Dragging controls from Object Library

这个是数据显示器,显示所有场景及其控件的结构。

Document outline

 

在IB中,这个位置显示的是你的NIB文件中的文件,而在Storyboard中这里显示的是ViewController,目前这里只有一个ViewController,我们接下来可能会增加一些。

这是一个文档管理器的缩小版,叫做dock。

 

The dock in the Storyboard Editor

 

Dock展示场景中第一级的控件,每个场景至少有一个ViewController和一个FirstReponder,但是也可以有其他的控件,Dock还用来简单的连接控件,如果你需要向ViewController传递一个关系时,只需要将其按住Ctrl键拖到ViewController上就可以了。

Note:你大概不会太长使用FirstResponder,因为它只是一个代理控件,代表着当前你所使用的控件。

现在运行这个应用,他会向我们设计的界面一样。

 

App with objects

 

 

如果你以前制作过NIB型的应用的话,你也许回去寻找MainWindow.xib ,这个文件包括所有的ViewController,Appdelegate等等,但是在Storyboard中这个特性已经被废止了。

 

No more MainWindow.xib

那么,没有这个文件,应用从那里起始呢?

让我们打开AppDelegate文件,看看那上面是怎么说的:

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

如果要使用Storyboard特性,那么AppDelegate必须继承自UIResponder类, 之前则是继承自NSObject类的,而且必须有一个不是UIOutlet类的Window属性声明才可以。

如果你再去看AppDelegate的执行文件,里面大概什么都没有,甚至连 application:didFinishLaunchingWithOptions: 也只是返回了一个 YES,而之前,这里则需声明一个ViewController并且将他设置成起始页面,但是现在这些都没有了。

秘密就在info.plist文件中, 打开Ratings-Info.plist (在 Supporting Files group里) 你就会看到这些:

 

Setting the main storyboard file base name in Info.plist

 

在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展示在屏幕上,不需要任何编程工作。

在项目总结面板上,你也可以看到并且编辑这些信息:

 

Setting Main Storyboard in Target summary

如果你还想设置nib文件的话,另外有地方去设置的。

为了完成这个实验性的小程序,我们打开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]).

与之前使用MainWindow.xib的一个最大的不同是:现在app delegate已经不是Storyboard的一部分了,这是因为app delegate不再从nib文件中,而侍从Storyboard中加载了,我们必须告诉 UIApplicationMain 我们的app delegate类的名字是什么,否则他将无法找到。

 

制作一个Tab类型的应用

 

本教程中的Rating App拥有两个Tab,在Storyboard中,很轻松就能够做出一个Tab视图。

回到MainStoryboard.storyboard中,直接从左边的Library拖进来一个TabViewController就可以了。

Adding a new tab bar controller into the Storyboard

 

新的Tab Bar Controller附带了两个View controller,分别作为Tab的视图使用,UITabBarController被称为包含视图,因为他包含这其他一些View,其他常见的包含视图还有那vi嘎提鸥鸟 Controller和SplitView Controller。

 

在iOS 5中,你还可以自己写一个自定义的Controller,这在以前是做不到的。

 

包含关系在Storyboard中用一下这种箭头表示。

 

Relationship arrow in the Storyboard editor

 

拉一个Label控件到第一个子试图中,命名为“First Tab”,再在第二个子视图中添加一个Label,命名为“Second Tab”。

注意:当屏幕的缩放大于100%时,你无法在单个场景中添加控件。

选中Tab Bar Controller,进入属性检查器,选中“作为起始场景”,如下图:

 

Is Initial View Controller attribute

 

现在那个没有头的虚虚的小箭头指向了Tab Bar Controller,说明他是起始场景。

 

Arrow indicating initial view controller in Storyboard editor

 

这意味着,当你启动这个应用的时候,UIApplication将会将这个场景作为应用的主屏幕。

Storyboard一定要有一个场景是起始场景才行。

现在运行试试吧

 

App with tab bar

code专门为创造这种Tab Bar的应用准备了一个模板,我们也可以使用他,但是自己有能力不用模板自己做一个Tab Bar也是不错的事。

 

 

如果你添加了多于五个子视图到一个TabBarcontroller的话,并不会创造五个Tab,第四个tab会自动变成More标签,不错吧

 

制作一个表格视图

 

目前连接到Tab bar Controller的视图都是普通的View Controller,现在,我要用一个TableViewController来代替其中的一个ViewController。

单击第一个视图并删除,从Library中拖出一个TableViewController。

 

 

Adding a new table view controller to the Storyboard

 

 

在选中这个TableViewController的前提下,从Library中拖出一个NavController,将会直接附着在上面。

Embedding in a navigation controller

 

当然也可以调换顺序,我完全没意见。

由于NavController和TabBarController一样也是一个包含控制器视图,所以他也必须包含另一个视图,你可以看到同样的箭头连接者这两个View。

 

View controller relationships in outline of Storyboard editor

 

请注意所有嵌套在NavController下的View都会有一个Navigation Bar,你无法移除它,因为他是一个虚拟的Bar。

 

如果你检视属性检测器,你就会发现所有bar的属性都在一起:

 

Simulated metrics in Storyboard editor

 

“Inferred”是Storyboard中的默认设置,他意味着继承的关系,但是你也可以改变他。但是请注意这些设置都是为了让你更好的进行设计和这样设置的,随意修改默认设置会带来不可遇见的后果,施主自重。

 

现在让我们把这个新的场景连接到Tab Bar Controller中,按住Ctrl拖动,或者右键。

 

 

Connecting scenes in the storyboard

当你放手的时候,一个提示框会出现。

Create relationship segue

当然是选第一个了,Relationship – viewControllers ,这将自动创建两个场景之间的关系。

 

Relationship arrow in the Storyboard editor

 

Rearranging tabs in the Storyboard editor

直接拖动就可以改变Tab Item的顺序,同时也会改变显示Tab的顺序,放在最左边的Tab会第一个显示。

 

现在运行试试看吧

App with table view

 

在我们在这个应用中加入任何实质性的功能之前,我们先来清理一下Storyboard,你不需要改变TabBarController中的任何内容而只需要改变他的子视图就可以了。

 

每当你连接一个新的视图到TabBarController中的时候,他就会自动增加一个Tab Item,你可以使用他的子视图来修改该Item的图片和名称。

 

在NavController中选中Tab Item并且在属性编辑其中将其修改为Player。

 

Setting the title of a Tab Bar Item

 

将第二个Tab Item命名为“Gesture”

我们接下来把自定义的图片加入到这些item中, 源码 中包含一个名为“Image”的文件夹,在那里你可以找到我们用到的资源。

接下来,将NavController的title改为Player,也可以使用代码··

 

Changing the title in a Navigation Item

 

运行看一看,难以置信吧,你到现在也没写一条代码。

App with the final tabs