キーボードを閉じる・開閉を検知する
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
が廃止になっているためおすすめできません。