连接界面(UI)到代码中
本文中将讲述连接FoodTracker应用的界面元素到程序代码中,定义一些用户能够在界面上执行的动作。
本文的学习目标
- 解释storyboard中一个scene和底层视图控制器(view controller)之间的关系
- storyboard上界面元素和源代码之间创建outlet和action的连接
- 处理用户在文本输入框的输入,在界面上显示结果
- 设计遵循一个协议的类
- 理解代理(delegation)模式
- 根据目标-动作(target-action)模式设计应用的架构
连接界面到源代码
在storyboard中,一个场景(scene)一般代表一个视图控制器(view controller),视图控制器实现了应用程序的行为。一个视图控制器管理着单个内容视图及其具有继承关系的子视图,协调应用程序数据模型(封装了应用的数据)信息的流向并在视图上显示数据,管理内容视图的生命周期,处理设备旋转产生的方向变化,定义应用程序中的界面导航,实现用户输入的响应行为。iOS中所有视图控制器对象都是UIViewController类或其子类。
代码中创建并实现自定义视图控制器的子类,建立类和storyboard中的场景之间的连接,关联代码中的行为到storyboard中的界面。
上一节的项目中,Xcode自动创建了定义ViewController类的swift源代码文件(ViewController.swift),并已连接到storyboard对应的一个视图场景。使用Identity Inspector编辑storyboard上界面元素的对象属性,例如所从属的类。
根据界面元素创建Outlets
打开主storyboard;
-
点击右上角的助手编辑器;
-
在编辑选择栏选中预览ViewController.swift;
-
在ViewController.swift代码中找到类的定义行;
class ViewController: UIViewController {
-
在定义行下面添加MARK注释行;
// MARK: Properties
带有“// MARK:”开头的注释是一种特殊的注释,用于组织代码和帮助导航到此处代码
-
在storyboard界面上选中文本输入框,按住Control键的同时鼠标拖拽至ViewController.swift文件中“// MARK: Properties”代码下面;
![Uploading 3_textfield_addoutlet_2x_321850.png . . .]
-
在出现的对话框中Name栏中输入nameTextField;
- 点击“Connect”按钮。
@IBOutlet weak var nameTextField: UITextField!
Xcode将增加一个用于指向文本对话框的相应代码到ViewController.swift文件中,并配置storyboard建立上述连接。
IBOutlet属性通知Xcode从界面编辑器(Interface Builder,前缀缩写IB)中连接到一个叫“nameTextField”的属性,weak关键字表明该属性有可能为nil,这个属性类型为UITextField,其最后的“!”是隐式解包可选类型。
连接标签到ViewController.swift代码中
-
选中storyboard中的标签对象,按住Control键的同时鼠标拖拽至ViewController.swift代码文件中声明nameTextField属性的代码下面;
-
在出现的对话框中Name栏中输入mealNameLabel;
- 点击“Connect”按钮。
同样,Xcode将增加一个用于指向标签的相应代码到ViewController.swift文件中,并配置storyboard建立上述连接,同文本输入框属性一样,只是属性名称叫“mealNameLabel”,类型是UILabel。@IBOutlet weak var mealNameLabel: UILabel!
定义一个要执行的动作(Action)
iOS应用程序是基于事件驱动编程(event-driven programming),即应用程序的执行流向是由事件决定:系统事件和用户动作。用户在界面上执行动作触发应用程序内的事件,这些事件导致应用程序的逻辑执行和数据处理操作,应用程序对用户动作的响应最终反映到界面中。
动作(Action)是一个代码片段,可以连接到出现在应用程序上的某个事件。当该事件发生时,这些代码得到执行。定义一个动作方法完成各种事务,如操作一个数据块或者更新界面等。使用动作响应用户或系统的事件,来驱动应用程序的执行流。创建一个动作类似于创建一个outlet。
创建一个标签重置动作(reset action)
- 在ViewController.swift类定义块“}”添加MARK Action注释代码;
// MARK: Actions
-
在storyboard中选中“设置缺省标签文字”按钮,按住Control键的同时鼠标拖拽至MARK Action注释代码下面;
- 在出现的对话框中,Connection栏选择Action;
- Name栏中输入“setDefaultLabelText”;
-
Type栏选择UIButton;
- 点击“Connection”按钮。
Type栏的缺省为AnyObject,Swift语言中AnyObject表明一个可以属于任何类的对象类型。Xcode将增加一段代码到ViewController.swift文件中,并配置动作方法。
> `@IBAction func setDefaultLabelText(sender: UIButton) {
}`
上面代码中,sender参数指向的对象导致触发了动作,本例是“设置缺省标签文字”按钮。IBAction属性表明本方法是一个从storyboard界面上连接的动作。
代码实现标签重置动作
- 在ViewController.swift找到刚才添加的setDefaultLabelText动作方法;
- 添加一行代码。
mealNameLabel.text = "Default Text"
上面完成的例子实现了iOS应用程序设计中的”目标-动作”(target-action)模式,该模式用于当一个指定事件发生时一个对象发送消息到另一个对象。本例中,这个事件是用户点击“设置缺省标签文字”按钮,动作是setDefaultLabelText,目标是ViewController(动作方法所在的类),发送着是“设置缺省标签文字”按钮。”目标-动作”模式中,消息是在代码中定义的一个动作方法,目标(target)是接收消息的对象-能够执行该动作的对象,发送动作消息的对象通常是一个控件(control),例如按钮、滑杆(slider)、切换器(switch)等-触发相应的事件:点击、拖拽或数值改变等。
处理用户输入
当处理接收用户在一个文本输入框的输入时,需要用到文本输入框代理(delegate)的一些帮助。当文本输入框的文本发生变化时或者发生重要事件如用户开始或终止编辑文本,会与其代理进行通信,代理可以使用这些信息在合适的时机保存或清除数据,关闭键盘屏幕等。任何对象作为另外一个对象的代理相当于其遵从适应的协议,一个定义文本输入框代理的协议名为UITextFieldDelegate,本例因为ViewController保持文本输入框的一个引用,将其作为文本输入框的代理,ViewController类采用UITextFieldDelegate协议。
采用UITextFieldDelegate协议
- 在ViewController.swift文件中找到class定义行;
- 使用”,”符号添加采用UITextFieldDelegate声明。
class ViewController: UIViewController, UITextFieldDelegate {
设置ViewController为文本输入框nameTextField的代理
- 在ViewController.swift文件中找到viewDidLoad()方法;
- 在代码行super.viewDidLoad()后面,添加下面代码。
nameTextField.delegate = self
self关键字引用ViewController类本,ViewController类就成为文本输入框nameTextField的代理。
实现UITextFieldDelegate协议方法
UITextFieldDelegate协议包含选项方法,采用该协议的类可以不提供选项方法的实现,本例为了完成一些行为,提供实现下面两个方法的实现。
func textFieldShouldReturn(textField: UITextField) -> Bool func textFieldDidEndEditing(textField: UITextField)
当用户点击一个文本输入框时,该输入框自动成为一个首响应者(first responder),第一个接收各种类型的应用事件,包括按键事件、移动事件和动作消息等。 文本输入框成为首响应者的一个结果就是,iOS系统会显示键盘小窗口,输入框开始一个编辑事务。当用户想要完成文本输入框的编辑,该输入框需要退出首响应者状态。因此上面两个协议方法的实现,会用于这个情况:用户点击一个按钮来结束文本输入框的编辑,这里用户点击“完成”(Done)或“返回”(Return),协议方法textFieldShouldReturn(_:)会被调用。
实现textFieldShouldReturn方法
-
在ViewController.swift文件中"//MARK:Actions"上面添加MARK注释代码如下
// MARK: UITextFieldDelegate
-
在下面输入“func textfieldS”会出现自动完成列表,显示推荐的方法,选择textFieldShouldReturn方法;
func textFieldShouldReturn(textField: UITextField) -> Bool { }
-
在textFieldShouldReturn方法中添加以下代码。
textField.resignFirstResponder() return true
-
完整的代码如下。
func textFieldShouldReturn(textField: UITextField) -> Bool { textField.resignFirstResponder() return true }
调用UITextField的resignFirstResponder方法退出首响应者状态,返回true表明文本输入框响应用户点击Return按键后关闭键盘小窗口。
实现textFieldDidEndEditing方法
文本输入框退出首响应者状态后,会调用textFieldDidEndEditing协议方法。
- 在ViewController.swift文件中,找到textFieldShouldReturn方法;
- 在其下面添加以下方法和代码。
func textFieldDidEndEditing(textField: UITextField) { mealNameLabel.text = textField.text }
运行模拟器