キーボードを閉じる・開閉を検知する
Published by @SoNiceInfo at 6/24/2020
テキスト入力で開いたキーボードを閉じる実装方法とキーボードの開閉を検知する方法を紹介します。
UIApplicationを拡張する
何気なく行っている「テキスト入力後に適当な場所をタップしてキーボードを閉じる」ですがiOSのキーボードのデフォルトの機能ではありません。
キーボードを閉じる機能はアプリ側で実装する必要があります。
さらにSwiftUIの標準機能では用意されていないのでUIApplicationを拡張して実装する必要があります。UIApplicationを拡張してキーボードを閉じる関数を作成します。
関数closeKeyboard()を定義してその中でsendActionでセレクターに対してアクションを送信します。UIResponder.resignFirstResponderにnilを設定することで、最上位のファーストレスポンダがnilとなります。
つまり、何もアクションしていない状態となりキーボードも閉じられます。
extension UIApplication {
func closeKeyboard() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}onTapGestureでタップを検知する
なにかをタップしたことを検知するには対象のViewに対してonTapGestureを設定してアクションを呼び出します。
ここではZStackで作った黄色い背景にonTapGestureを仕込んでいます。
その中でUIApplication.shared.closeKeyboard()を呼び出すことで、黄色い背景をタップするとキーボードが閉じます。
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
@State var name: String = ""
var body: some View {
ZStack {
Color.yellow
.opacity(0.4)
.edgesIgnoringSafeArea(.all)
// ここが大事
.onTapGesture {
UIApplication.shared.closeKeyboard()
}
VStack {
Text("Result: ") + Text(name)
TextField("Placeholder", text: $name)
.padding()
.border(Color.green, width: CGFloat(2))
}
}
}
}
// ここが大事
extension UIApplication {
func closeKeyboard() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
キーボードの開閉を検知する
キーボードの状態を検知して動作を実装する方法を紹介します。
キーボードに限らずなにかの動きを検知するにはonReceiveを使います。onReceiveを使うとpublisherからのイベント発生通知を検知できるようになります。
JavaScriptでいうイベントリスナーみたいなものだなと思いました。
キーボードが開いたことはUIResponder.keyboardDidShowNotification、 閉じたことはUIResponder.keyboardDidHideNotificationでそれぞれ検知します。
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardDidShowNotification)) { _ in
// Write code for keyboard opened.
}.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardDidHideNotification)) { _ in
// Write code for keyboard closed.
}以下にキーボード周りの通知をまとめます。
| 開く | UIResponder.keyboardWillShowNotification |
| 開いた | UIResponder.keyboardDidShowNotification |
| 閉じる | UIResponder.keyboardWillHideNotification |
| 閉じた | UIResponder.keyboardDidHideNotification |
| 変化する | UIResponder.keyboardWillChangeFrameNotification |
| 変化した | UIResponder.keyboardDidChangeFrameNotification |
これを使うと上記プログラムに追加してキーボードが閉じてるときはClosed, 開いてるときはOpenedと表示するプログラムが書けます。
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
@State var name: String = ""
@State var state: String = "Closed"
var body: some View {
ZStack {
Color.yellow
.opacity(0.4)
.edgesIgnoringSafeArea(.all)
// ここが大事
.onTapGesture {
UIApplication.shared.closeKeyboard()
}
VStack {
Text("Result: ") + Text(name)
TextField("Placeholder", text: $name)
.padding()
.border(Color.green, width: CGFloat(2))
Text("Keyboard: ") + Text(state)
}
}.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardDidShowNotification)) { _ in
self.state = "Opened"
}.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardDidHideNotification)) { _ in
self.state = "Closed"
}
}
}
// ここが大事
extension UIApplication {
func closeKeyboard() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
その他
他のサイトではUIApplication.shared.keyWindow?.endEditing(true)を呼び出す方法が紹介されています。
この方法だとiOS13でUIApplication.shared.keyWindowが廃止になっているためおすすめできません。

