配置视图
提供了一些对象的库,可以让你添加到故事板文件中. 有些是用户界面元素属于视图的,比如按钮和文本框.还有一些其他更高级的对象,比如视图控制器和手势识别器.
这个Hello World View Controller场景已经包含了一个视图. 现在你需要添加一个按钮,一个标签,和一个文本框. 然后, 您在这些元素和视图控制器类之间建立连接,这样这些元素就能提供给你需要的行为.
添加用户界面元素
你可以通过从对象库拖拽这些界面元素到画布的视图上面,来添加用户界面(UI)元素. 这些UI元素拖拽到视图后, 你就可以对这些元素进行适当的移动及调整大小.
在你添加完文本框,标签,及按钮的UI元素并按照上述建议改变布局后,你的工程应该会看起来像下图这样:
你可以给文本框改变几个地方它的行为可以表现的和用户期待的那样. 首先,因为用户将会输入他们的名字,因此你要确保iOS建议他们所输入的每一个单词都是大写开头的. 其次,你要确保键盘与文本框为输入名字所作的配置相关联(例如 不能是数字),并且要在键盘上显示一个Done按钮.
这个就是更改这些的原因: 因为在设计的时候,你是知道文本框将要包含哪种类型的信息的,因此你可以配置它以便让它在运行时的外观与行为可以适合用户的操作.你在属性察看器中改变这些配置.
运行你的应用来确定你所添加UI元素是否和你期待的一样. 如果点击Hello按钮,它应该会变成高亮,并且如果在文本框内部点击,则键盘应该会显示出来. 目前, 按钮不做任何事,标签为空,以及没有任何方法可以在键盘显示后关闭它. 要添加这个功能,你需要去在UI元素与视图控制器之间建立连接. 这个连接将会在下一节描述.
为按钮创建一个动作(Action)
当用户激活一个UI元素的时候,这个元素会发送一个动作(action)消息到一个知道如何处理相应动作的对象的函数中(例如 "添加这个联系人到用户联系人列表").这个交互是target-action机制,是另一个Cocoa Touch的设计模式.
在这个教程中, 当你触控按钮的时候, 你希望它发送一个 "改变问候语" 的消息(这是action) 到视图控制器中(这是 target). 这个视图控制器将会通过改变它所管理的字符串(这里表示 模型对象)来响应这个消息. 然后,视图控制器用这个模型对象的值来更新标签所显示的文本来反映出这个改变.
你可以通过Control+拖拽的方式,将画布的元素拖拽到适当的源文件中(通常,是一个视图控制器的源文件),以此来为一个UI元素添加一个动作和设置相应的动作函数.故事板保存着你以这种方式创建的连接. 以后,当应用加载故事板的时候,会重新建立这个连接.
当你Control+拖拽这个Hello按钮到HelloWorldViewController.m文件的类的扩展并且设置了产生的动作,那么你已经做了两件事了: 你通过Xcode在视图控制器的类中(在HelloWorldViewController.m中)添加了适当的代码,并且你在按钮与视图控制器之间创建了一个连接.Xcode会明确地做如下几件事:
-
查看HelloWorldViewController.m,它在类的扩展中添加了如下动作函数的声明:
- (IBAction)changeGreeting:(id)sender; //这段代码在类的扩展生成
并且在实现区域中添加了下列空实现的函数:
- (IBAction)changeGreeting:(id)sender { //这段代码会实现部分生成
}
-
它在按钮和视图控制器之间创建一个连接.
接下来,你要在视图控制器和剩余的两个UI元素进行连接(也就是 标签和文本框).
给文本框与标签创建出口变量(Outlets)
一个出口变量(outlet) 描述了两个对象间的连接. 当你想让一个对象(例如 视图控制器)去传递一个它获取到的对象(例如 文本框)的时候,你将这个被获取的对象(例如 文本框)指定为一个出口变量(outlet). 当应用程序运行时,Xcode将会重新建立你所创建的出口变量,允许在运行时对象间进行互相传递.
在这个教程中,你希望视图控制器获取用户在文本框中输入的文本,然后显示在标签上. 要确保视图控制器可以传递这些对象,你要在他们之间去创建出口变量(outlet).
这一步你要去添加文本框与标签的出口变量,它和你刚才添加按钮的动作的操作非常相似. 在你添加之前, 确保这个主故事板文件的画布是可视的并且在助理编辑器中HelloWorldViewController.m仍然被打开着.
通过添加文本框的一个出口变量(outlet)你已经完成了两件事, 如下:
-
Xcode在视图控制器类的实现文件(HelloWorldViewController.m)中,添加了适当的代码.
实际上,它就是在类扩展里加入了如下代码:
@property (weak, nonatomic) IBOutlet UITextField *textField;
在viewDidUnload函数中添加如下表达式:
self setTextField:nil;
这个viewDidUnload函数是你在Xcode所选择的模板为你提供的,而且这个函数是通过UIKit框架为你实现的. 一个视图控制器当它需要卸载掉它所包含的视图时,就会调用viewDidUnload函数, 因此在这个函数将视图的出口变量(outlet)设置为nil才是正确的.
-
Xcode从视图控制器到文本框创建了一个连接.
通过在视图控制器和文本框之间创建连接, 用户输入的文本可以传递到视图控制器中. 当Xcode已经生成changeGreeting:函数声明的时候,表示连接已经创建了,这时候会再文本字段(Text Field)声明的左边会显示一个已经被填充的圆形.
注意: 早期的Xcode版本会在你使用Control+拖拽方法的时候,给你在实现块(implementation block)中给你的每一个声明的属性(property)添加一个@synthesize指令. 因为编译器会自动合成存取器函数(synthesizes accessor methods),因此这个指令已经没有必要了. 你可以很放心的删除它们了.
现在来添加一个标签的出口变量(outlet)并设置连接. 在视图控制器和标签之间建立连接, 可以让视图控制器用获取到的用户输入的文本来更新标签的内容. 这一步的过程和你之前添加文本框的出口变量(outlet)是一样的, 不过还要适当的更改下连接的设置. (确保助手编辑器仍然显示着HelloWorldViewController.m文件.)
通过这个教程,你目前为止已经创建了总共三个连接到你的视图控制器中了:
-
一个按钮的动作(action)连接
-
一个文本框的出口变量(outlet)连接
-
一个标签的出口变量(outlet)连接
你可以在连接察看器(Connections inspector)上检查一下这些连接.
在连接察看器中,Xcode显示所选对象的连接 (在这个情况下, 显示的是视图控制器的连接). In your workspace window在工作区窗口,你应该会看到类似于下图这样的:
你会看到视图控制器和它的视图之间有一个连接,另外还可以看见你所创建的三个连接. Xcode会提供一个默认的 视图控制器与它视图间的连接; 你无法用任何方式访问它.
建立文本框的代理连接(Delegate Connection)
在你的应用中,你已经创建了超过一个连接了: 你需要去连接文本框到一个作为文本框代理的对象上面.在这个教程中,你实用视图控制器来作为文本框的代理
你需要指定一个文本框的代理. 这是因为当用户触控键盘上的Done键时,这个文本框会向代理发送一个消息 (回忆一下之前所讲述的吧, 一个代理就是一个对象,这个对象代表着另外一个对象的动作. 在这里就是视图控制器为代理,而另一个对象则是文本框). 在稍后的步骤中,你将会使用与这个消息所关联的函数来让键盘消失.
确保故事板文件已经在画布上打开了. 如果还没有打开,在工程导航器中选择MainStoryboard.storyboard.
测试应用
点击Run并测试你的应用.
你应该会发现当你点击按钮时,它会高亮. 你还会发现如果点击文本框的时候,键盘会显示出来并可以输入文本. 但是你还是没有方法可以让键盘消失掉. 要做到这一点,你需要去实现相关的代理函数才行. 你会在下一章来做这件事. 现在,关掉模拟器.
概括
当你在画布的视图控制器与助手编辑器中实现文件(HelloWorldViewController.m)的类扩展之间创建了一个适当的连接的时候. 也会更新了实现文件来支持 出口变量(outlet)以及动作(action).
如果当创建一个连接的时候,没有使用Xcode的自动添加代码的功能(也就是 创建连接时 从画布上通过按住Control键并拖拽到源文件中这种方式). 你也可以去在类扩展或自身的头文件中 手动编写属性和函数声明,然后和你所做的文本框代理之间创建连接. 不过通常情况下你让Xcode帮你做这些工作比较好,这回减少错误(并且可以少打字).