處理用戶輸入
現在,用戶可以重置菜品名稱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按鈕回到標準編輯器。
image: ../Art/standard_toggle_2x.png - 在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到你的源代碼。你也添加了用來在用戶和控件交互的時候更新用戶界面的代碼?,F在項目仍然相當簡單,只有一個場景,但是在接下來的課程中,你將繼續添加功能,并增加它的復雜性。
注意
要想看本課完整的例子項目,下載這個文件并在Xcode中查看。
(本節完畢。明天會添加圖片拾取器。)