[SwiftUI] 收鍵盤的小技巧

戴萌
Jun 13, 2021

關於收鍵盤的情況,最常遇見的要求是當鍵盤升起來的時候,能點擊鍵盤以外的其他地方就把鍵盤收下去,明明APPLE 給的原生元件並沒有這樣的功能,但是這樣的操作行為不知何時就變成了標配,只有要鍵盤就要有這樣的功能

在先前使用UIKit 的時候,最簡單的方式就是呼叫

textField.resignFirstResponder()

或是在UIViewController 的 View 中加上 TapGesture 呼叫

self.view.endEditing(true)

這二種方式就可以收鍵盤。

但是在SwiftUI 中就不是這麼適用了,原因是在 SwiftUI 中 View 的定義不一樣了,並不會有像UIView這樣的東西,取而代之的是 ZStack、 VStack、HStack。

那…怎麼做比較好呢?

先簡單說一下SwiftUI View 與 View 之間的關係,可以想像是你在做一本透明底的書,從封面看下去就是APP 畫面,如果有在用PhotoShop之類的軟體,SwiftUI 的 View 就像圖層,雖然原本的UIKit 也有一點圖層的感覺,但是SwiftUI 更像而且就是像用一張一張透明紙疊出來的結果。

在UIKit 如果想要在點擊其他地方就收鍵盤的話,會在View 上加上TapGesture ,就用這樣思考方式用在SwiftUI的話,可以建立二個ZStack ,一個當成背景,一個當成內容,在當作背景的ZStack 上加 Tap Gesture,不過這樣的Code 不是很好看,也不太像SwiftUI

簡單說一下 ZStack ,就是元件會以Z軸排列,所以元件與元件是會相疊在一起的

這時候就要用到 Spacer,簡單來說 Spacer 就是可以幫你補足空間的元件,UIKit 的時候就有這樣的東西,但是大多是用在NavigationBar Item 且不是很好用…

SwiftUI的Spacer 相對上來說就很好用,它可以自定大小、顏色也可以給它Tap Gesture ,所以可以把它拿來做背景

以ZStack 來說,寫在上面的會在底層,因此上述的Code,Spacer 會在TextField底層

為了能讓Spacer 變成背景加上了一些設定

.frame(maxWidth: .infinity, maxHeight: .infinity)

是為了讓Spacer 的Frame為與螢幕畫面一樣,將 maxWidth, maxHeight 設為 .infinity

.contentShape(Rectangle())

為了讓Spacer 能被點擊到,設定 ContentShape 為 Rectangle

.onTapGesture {                                   
hideKeyboard()
}

Spacer 加上 onTapGesture 賦予它點擊事件

最後 hideKeyboard()寫上 View 的 Extension ,由 UIApplication sendAction -> UIResponder.resignFirstResponder(),本來resignFirstResponder就是屬於UIResponder 的,由UIApplication 去執行就可以把鍵盤收起來

最後的最後附上範例程式,範例中為了做比較好的排版,在TextField 上又加上了ZStack。

--

--