要聊到Keyboard-Related Properties,就不能不說說住海邊的UITextFieldDelegate。
textField使用他的delegate來管理內容。
當使用者與textField互動時,textField便會發送delegate,讓他有機會對接下來發生的事情做控制,真是個討厭的抓耙子。
你可以使用delegate裡的方法來管理使用者能否開始或結束編輯,或是在使用者輸入時驗證內容。例如輸入帳號密碼時同步通知格式不符,或是限制最大輸入字數等等都是用delegate實現的,非常的住海邊,感覺就是個會情緒勒索的父母。
先來說說讓鍵盤彈出和收回的原理-first responder。
當textField變成first responder的時候,系統會自動跳出鍵盤,並將鍵盤輸入的內容回饋到textField裡。
一般當你點擊textField的時候,textField就會變成first responder;但如果你要強迫使用者輸入訊息的話,也可以使用becomeFirstResponder()這個方法來讓textField變成first responder喔!
例如我們在viewDidLoad()裡對idTextField呼叫becomeFirstResponder():
我才剛打開app什麼也還沒做,就馬上跳鍵盤出來叫我編輯帳號,也太霸道了,都不管人家受不受得了!
如果需要隱藏鍵盤的話,可以呼叫resignFirstResponder()這個方法來使textField從first responder的身份中退出。你可以設定使用者某些特定的動作會使鍵盤收起,例如點擊return。
但我要怎麼知道使用者點擊了return?這就需要UITextFieldDelegate的幫忙了。
當class繼承了UITextFieldDelegate,只要使用者操作相關的互動,textField就會傳送一個delegate給UITextFieldDelegate,並呼叫相對應的function,你可以在function內定義響應的動作。
就本次案例來說,我們希望使用者點擊return後收回鍵盤,而使用者點擊return後,textField會發送delegate並呼叫textFieldShouldReturn(:)。
所以我們在textFieldShouldReturn(:)裡定義resignFirstResponder()並回傳true。
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
還沒結束呢!接下來我們要讓class繼承UITextFieldDelegate:
class ViewController: UIViewController, UITextFieldDelegate {}
並決定有哪些textField要啟用ViewController所繼承的Delegate。
idTextField.delegate = self
在這裡我們只讓idTextField啟用delegate來比較看看差異。
啟用了delegate的idTextField一點擊return就馬上收回了鍵盤,但沒有繼承的passwordTextField怎麼點94收不起來,ㄎ憐。
以下是textField發出delegate並呼叫function的程序:
來實作一波限制字數的功能,在textField(_:shouldChangeCharactersIn:replacementString:)裡加入響應的動作:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let countOfWords = textField.text!.count - range.length + string.count
if countOfWords > 10 {
return false
}
wordsCountingLabel.text = "\(countOfWords) / 10"
return true
}
其中range是要被取代的字元,string是取代的新字串,總字數就是countOfWords。
當你的編輯會使countOfWords大於10的時候,function就會回傳false,禁止你此次的編輯生效。
不知道大家有沒有發現,我鍵盤都已經彈出來了,textField還傻傻的待在原地不知道要跑。現在是還沒有被鍵盤遮到啦,如果有一天被遮到了呢!!(家長語氣)
所以這時候就必須更新介面來確保textField的編輯是可視的。
apple提供了一些關於鍵盤的通知,讓你可以在接收到這些通知後對視圖進行更新:
每個通知裡都有一個包含鍵盤大小的userInfo,可以利用這個參數重新調整你的畫面位置以避免畫面被鍵盤遮擋。
一般的狀況下可以重新定義view的大小,將view的大小減去鍵盤的高度;而視圖是嵌入scrollView裡的話,則可以將畫面向上捲動鍵盤大小的距離,看起來就像視圖跟著鍵盤移動了~
(圖片來源:UITextField)
因為scrollView在第15天左右才會講到,大家應該還不是很熟悉,所以就先示範第一種狀況就好(迴避眼神)。
首先先建立2個當中心收到通知後會呼叫的function:
@objc func keyboardShow(_ notification: Notification) {
//從userInfo中取得鍵盤的frame -> size
let userInfo = notification.userInfo!
let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let intersection = keyboardSize.intersection(view.frame)
view.frame.size = CGSize(width: view.frame.width, height: view.frame.height - intersection.height)
newTextField.center = CGPoint(x: view.frame.width / 2, y: view.frame.height / 2)
}
@objc func keyboardHide(_ notification: Notification) {
view.frame.size = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
newTextField.center = CGPoint(x: view.frame.width / 2, y: view.frame.height / 2)
}
剛剛提到每個通知裡都有一個包含鍵盤大小的userInfo,所以當keyboard彈出的的時候,先從userInfo裡取出鍵盤的size,再用他resize畫面大小及reposition textField的位置。
而當鍵盤退出的時候,讓畫面恢復至螢幕的大小,再回復textField的位置。
接下來加入2個通知,讓viewController成為觀察者,如果觀察到指定的notification,就會執行相對應的selector function。
這裡我們設定觀察到keyboardWillShowNotification時執行keyboardShow(:),觀察到keyboardWillHideNotification時執行keyboardHide(:)。而object決定了觀察者只接受誰發出來的通知,如果設定為nil他就不會啟動篩選,也就是只要收到通知,不管是誰發出來的都OK。
NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
textField實作了一個叫做UITextInputTraits的protocol,裡面的屬性可以客製化textField的鍵盤。除了使用者當前語言的標準鍵盤以外,還提供了數字、URL、e-mail等特定訊息的專用鍵盤,你可以利用這個protocol裡的屬性去調整鍵盤。
這個function決定了你自動大寫的時機,有allCharacters(全大寫)、none(全小寫)、sentences(句子首字大寫)和words(單字首字大寫)四種。使用autocapitalizationType這個變數。
預設是sentences,這裡demo單字首字大寫:
newTextField.autocapitalizationType = .words
有時候只是想打siu恥,系統就自動幫你變成sounds恥,是在sounds幾點的啦!火星文錯了嗎?
這個就是correction幹的好事!autoCorrection會偵測你所輸入的文字,列出相依性高的單字們。於是在你打出一個單字庫裡沒有的字時,他就會自動幫你切換成相依性最高的那一個,根本是火星文殺手!
(怨念很深)
這個時候只要把autocorrectionType設為no,系統就不會再雞婆了!!哈哈!!
而有時打出單字庫裡沒有的字時下標會出現紅色毛毛蟲,這就是拼字檢查。
newTextField.autocorrectionType = .no
newTextField.spellCheckingType = .yes
範例中我把自動校正關掉了,所以就算打siu他也不會給我改掉,但我拼字檢查還開著,所以會出現紅色毛毛蟲。
Correction和Spell Checking裡除了yes與no之外還有default,Correction的default會由系統決定要不要開啟自動校正,怎麼聽起來毛毛的...
而Spell Checking的default則是由Correction決定,Correction是yes他就yes,是no他就no,愛哭愛跟路。
apple除了使用者所在地區的預設鍵盤外,還提供了很多有趣的鍵盤。像是數字only鍵盤、e-mail鍵盤(@在第一頁)、URL鍵盤(一鍵 .com)等等。因為實在是太多了,就不一一demo了,大家可以每個選來玩玩看,用keyboardType這個變數指定。
appearance決定了鍵盤的外觀,預設是light,也有dark可以選擇,超炫砲的。
newTextField.keyboardAppearance = .dark
apple也為return這個鍵提供了很多樣式,全部的鍵只有他有,就他最特別。
使用returnKeyType這個變數指定,其實也沒什麼大不了的,就你選哪個type,按鍵上就寫什麼字。除了continue、return和next是灰色以外,其他的形式都是藍色的。不過不管你改成怎樣的形式,都還是會響應textFieldShouldReturn(_:)這個function。
呼~終於講完Keyboard-Related Properties了,花了很多時間理解delegate,但覺得很有收穫。
下一回是UITextField的精采大結局,會講overlay和其他額外的特性,大家不要錯過喔~