处理用户输入
现在,用户可以重置菜品名称label的默认值,但是你真正想要的是让用户使用text filed来输入他们自己的菜品名。为了简单起见,让用户在text field中输入文本,然后点击回车键,更新mealNameLabel对象的text属性值。
当要接收来自text filed的用户输入的时,你需要一些来自text field delegate的帮助。Delegate(代理)是一个代表另一个对象或与另一个对象协同工作的对象。委托对象(在本例中为text field)保留另一个代理对象(代理,delegate)的引用,并且在适当的时候,这个委托对象会发送一个消息给代理。这条消息告诉代理关于委托对象要处理或者刚刚处理的事件。代理可以作出响应,例如,更新自身或者其他对象的外观或状态,或者返回一个值,这个值会影响一个即将到来的事件会被如何处理。
当用户编辑文本的时候,text filed的delegate会和text field进行通信,并且知道重要的事件何时发生,例如用户何时开始或结束编辑文本。Delegate可以使用这些信息在合适的时候保存或清除数据、移除键盘等等。
任何对象都可以成为另一个对象的代理,只要它遵守合适的协议(protocol)。定义了text filed代理方法的协议称为UITextFieldDelegate。使用视图控制器作为它管理的对象的代理是很常见的。在本例中,你将使用ViewController实例作为text filed的代理。
首先,ViewController需要遵守UITextFieldDelegate协议。只要把协议列在类声明行里既可以表示遵守了协议。
采用UITextFieldDelegate协议
-
如果助理视图还开着,点击Standard按钮回到标准编辑器。
- 在Xcode工具条中点击Navigator和Utilities按钮展开project navigator和utility area。
- 在project navigator,选择ViewController.swift。
- 在ViewController.swift,找到class行,它看上去是这样的:
class ViewController: UIViewController {
- 在UIViewController后 main,添加一个逗号(,)和UITextFieldDelegate来遵守协议。
class ViewController: UIViewController, UITextFieldDelegate {
通过遵守UITextFieldDelegate协议,你告诉了编译器ViewController类会作为有效的text filed 的代理来做事。这意味着,你可以实现协议的方法来处理文本输入,并且可以指定ViewController类的实例作为text field的代理。
设置ViewController对象作为它的nameTextField属性的代理
- 在ViewController.swift中,找到viewDidLoad()方法,它看上去是这样的:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
这个方法的模版实现包含一个注释。你不需要这个注视,先删掉它。
- 在super.viewDidLoad()的下方,空一行然后添加下面这段代码:
// Handle the text field’s user input through delegate callbacks.
nameTextField.delegate = self
self指向ViewController类,这是因为它只在ViewController类定义的范围内被引用。你可以添加自己的注释来帮助理解代码的作用。
现在viewDidLoad()方法看上去是这样的:
override func viewDidLoad() {
super.viewDidLoad()
// Handle the text field’s user input through delegate callbacks.
nameTextField.delegate = self
}
当ViewController实例被加载时,它设置它自己作为属性nameTextField的代理。
UITextFieldDelegate协议定义了八个可选方法。只需要实现那些你想要的行为即可。这儿,你需要实现下面两个方法:
func textFieldShouldReturn(_ textField: UITextField) -> Bool
func textFieldDidEndEditing(_ textField: UITextField)
为了理解这些方法何时被调用以及它们需要做什么,则需要了解text field如何响应用户的行为。当用户点击text field的时候,它自动成为第一响应者。在一个应用中,第一响应者(first responder)是一个排在首位去接收各种应用事件的对象,包括键盘事件、运动时间、以及action消息等等。换句话说,很多用户产生的事件最初都要路由给第一响应者。
作为text field成为第一响应者的结果,iOS显示了键盘,并且text field开始了编辑会话。用户使用键盘输入的内容被插入到了text field中。
当用户想结束text field编辑,text field需要注销它的第一响应者状态。因为text filed将不再是应用的活动对象,事件需要被路由到其他更合适的对象。
这时就需要实现UITextFieldDelegate方法了。当用户点击按钮结束text filed的编辑时,你必须让text field注销它的第一响应者状态。你要在textFieldShouldReturn(_:)方法里做这些,这个方法会在用户点击键盘上的Return(或者像本例中的,Done)按钮时被调用。
实现UITextFieldDelegate协议的textFieldShouldReturn(_:)方法
- 在ViewController.swift中,在// MARK: Actions部分的上面,添加下面这个注释:
//MARK: UITextFieldDelegate
这个注释用来组织你的代码,并帮助你(以及任何读你代码的人)导航它。
迄今你已经添加了好几个这样的注释。Xcode会在源码文件的函数菜单(Functions menu) 菜单中将这些注释罗列为每一部分的标题,这个列表会在你点击编辑区域顶部的文件名的时候出现。函数菜单让你可以在代码中快速跳到特定部分。你注意到这些部分是你之前用//MARK:标记的。点击一个部分的标题就可以跳到文件中的相应部分。
2 在注释的下面,添加下面这个方法:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
}
3 在这个方法中,添加下面的方法来注销text filed的第一响应者状态,并且添加一个注释来描述这段代码所做的事:
// Hide the keyboard.
textField.resignFirstResponder()
尝试键入第二行代码而不是复制粘贴。你将发现代码补全(code completion)是一个可以大大节约时间的Xcode功能。当Xcode带有潜在的补全列表时,滚动这个列表直到找到你想要的那个然后按下回车键。Xcode会为你把整行插入。
4 在这个方法中,添加下面这行代码:
return true
这个方法返回一个布尔值来表明是否系统应该处理按下Return键的行为。在本例中,你始终要响应用户按下Return键,所以要键入true。
现在你的textFieldShouldReturn(_:)方法应该是这个样子了:
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Hide the keyboard.
textField.resignFirstResponder()
return true
}
你需要实现的第二个方法,textFieldDidEndEditing(_:),它在text field注销了它的第一响应者状态的时候被调用。因为你是在textFieldShouldReturn方法中注销第一响应者状态的,所以系统调用者个方法是调用textFieldShouldReturn发发之后紧接着进行的。
textFieldDidEndEditing(_:)方法给了你一个机会来读取在text field中输入的信息以及对这些信息进行操作。在本例中,你将获取text field中的文本并用它修改你的label的值。
实现UITextFieldDelegate协议的textFieldDidEndEditing(_:)方法
- 在ViewController.swift中,在textFieldShouldReturn(_:)方法后面,添加如下方法:
func textFieldDidEndEditing(_ textField: UITextField) {
}
- 在这个方法中,添加下面这行代码:
mealNameLabel.text = textField.text
你只需做这些就能看到结果了。你的textFieldDidEndEditing(_:)方法看上去应该如下:
func textFieldDidEndEditing(_ textField: UITextField) {
mealNameLabel.text = textField.text
}
检查点:运行模拟器来测试你的改变。你能选择text field并键入文本。当你点击Done按钮的时候,键盘会缩回,并且label的文本变为现实在text field上的文本。当你点击Set Defautl Label Text 按钮的时候,这个label显示的文字从当前的文字变成Default Text(这个值你之前设置在了action方法里)。
小结
在本课中,你使用了助理编辑器添加outlets和actions到你的源代码。你也添加了用来在用户和控件交互的时候更新用户界面的代码。现在项目仍然相当简单,只有一个场景,但是在接下来的课程中,你将继续添加功能,并增加它的复杂性。
注意
要想看本课完整的例子项目,下载这个文件并在Xcode中查看。
(本节完毕。明天会添加图片拾取器。)