使用 ScrollView 讓 textField 在輸入時不在被阻擋
相信畫面中有輸入框
textField
是一件非常正常的事,而我們也會透過一些簡單的位移效果讓輸入框不被擋住。但是,在我隕石開發期間,有個需求希望輸入框輸入時,要看到其他所有的輸入框和某個按鈕,但是他們之前的總距離已經超過整個畫面扣掉鍵盤的高度,加上每個機型畫面高度也不同,是要我怎麼推 QQ
相信大家都有做過「鍵盤出現,畫面上移」這項功能,但某些時候這種方式可能太過於死板,變成每次都是移動特定高度。但我們有一個很棒的方式克服這一點,那就是把畫面 Embed 到 ScrollView
中,不僅有推動畫面的效果,使用者也可以自行調整目前位置,接著就讓我們來看看如何實作吧。
首先我們簡單設計我們的畫面,這邊我的畫面如下(為了實測 textField 會被鍵盤擋住,所以把輸入框放在下方):
為了配合 ScrollView
使用,首先我們將畫面中的所有元件 Embed 到一個 View
中,並且讓這個 View
也 Embed 到一個 ScrollView
中,畫面結構如下:
因為我們必須掌握鍵盤事件,所以在這邊我們會新增 Observer 來觀察鍵盤事件,當然也別忘了在離開畫面時移除 Observer 取消觀察鍵盤通知:
首先我們建立 keyboardWasShown
函數,當鍵盤將出現時會執行它:
首先我們透過通知的 userInfo
獲取到鍵盤的 size,同時建立一個將 scrollView
的 contentInset
的 bottom
距離設為鍵盤高度,而我們就是藉由這個方式推動我們的畫面。當然你也可以設定其他的高度,不一定要是鍵盤。
而鍵盤將隱藏時,我們也會有一個 keyboardWillBeHidden
函數,來將 contentInset
調整回一開始的 .zero
:
我們可以在 scrollView
上設置一個 tap
手勢,讓使用者可以點擊畫面來關閉鍵盤,我們直接呼叫 endEditing 方法即可:
讓我們測試一下剛剛設置的鍵盤推動跟關閉手勢是否有效果吧:
Mmmm...看起來似乎可以成功推動畫面,並且我們也能自由滾動畫面,但好像還可以更好。
你可以發現我們鍵盤出現時是有推動畫面的沒錯,但是他的位置可能還是稍微遮擋住下方的 textField,導致無法點擊到它,如下圖鍵盤還是擋住了第三個輸入框:
因此如果我們有一個方式可以按下按鈕就自動跳轉到下一個輸入框的話,那整體的操作流程會更加流暢,就讓我們來試試看吧!
首先我們把前兩個輸入框的 return key
都改為 next
,而最後一個輸入框為 done
。接著我們將這三個程式碼按照其順序在程式碼中建立一個 Outlet Colletion:
接著設置這三個 textField
的 delegate
,並且遵循 UITextFieldDelegate
實作其中的 textFieldShouldReturn
方法:
首先我們先獲取當前 textField
的 index
,之後透過 cotains 方法判斷 nextIndex
是否包含在 textField.indices
的範圍中,如果有就讓 textFields[nextIndex]
的 textField
設為 firstResponder,如果沒有的話我們則讓當前的 textField
取消 firstResponser,同時鍵盤也會關閉。
讓我們看看成果吧!
有時候在管理鍵盤收合是一件蠻麻煩的事情,但是如果我們把畫面 Embed 到一個 ScrollView
中,不僅可以推動畫面,同時也可以讓使用者自由滾動畫面,在最後我們還能夠配合鍵盤上的 return
按鈕讓畫面移動到下一個 textField
上。如果你有更好的方式管理鍵盤收合的方式,也歡迎與我交流分享。
你的keyboardWasShown看起來是推一個固定高度
但是你的示意圖看起來還有經過判斷才能做到是否要推還有要推多少?是否有藏招嫌疑
還有我現在才知道原來@Iboutlet可以用array 太神奇了
雖然我沒在用story board就4了
陳董粉絲又出現啦 xDD
這邊能夠做出推畫面的效果是因為在 ScrollView 中對 TextField 使用 becomeFirstResponder 的原因。
當初是參照這篇 Apple 官方文件來做的,後來發現沒有使用 scrollRectToVisible
也有效果也覺得蠻奇妙的。
有幾篇文章也是有發生類似這種自動滾動的事情:
Unwanted automatic scrolling with UIScrollView and UITextFields as subviews