Close Keyboard & Detect Keyboard Open/Close

Published by @SoNiceInfo at 6/24/2020


I'll show you how to implement closing an open keyboard after entering text and how to detect the keyboard's opening and closing.

Extend UIApplication

"Taping some area to close keyboard" is not derivered by iOS by default. So you need to implement it.
You need to extends UIApplication as it's not provided in SwiftUI's standard functionality.

Define closeKeyboard() and sendAction to the selector.
By setting nil to UIResponder.resignFirstResponder, top of the first responder become nil.
This means no action occured, thus keyboard will be closed.

extension UIApplication {
    func closeKeyboard() {
        sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}

Use function with onTapGesture

To detect user tapping, use onTapGesture to perform an action.
In this case, onTapGesture is applied to the yellow background in ZStack.
With UIApplication.shared.closeKeyboard() in it, users can close keyboard with tappig yellow background.

//
//  ContentView.swift
//

import SwiftUI

struct ContentView: View {
    @State var name: String = ""

    var body: some View {
        ZStack {
            Color.yellow
                .opacity(0.4)
                .edgesIgnoringSafeArea(.all)
                // Here is the point
                .onTapGesture {
                    UIApplication.shared.closeKeyboard()
                }
            
            VStack {
                Text("Result: ") + Text(name)
                TextField("Placeholder", text: $name)
                    .padding()
                    .border(Color.green, width: CGFloat(2))
            }
        }
    }
}

// Here is the point
extension UIApplication {
    func closeKeyboard() {
        sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
An image of demo of close keyboard

Detect keyboard open/close

Next step, I'll show you how to detect keyboard is opening, closing.
onReceive is usable to detect some event changing from publisher not only keyboard.

For example, use UIResponder.keyboardDidShowNotification to detect keyboard opened, use UIResponder.keyboardDidHideNotification to detect keyboard closed.

.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.
}

Here is the publisher around keyboard events.

OpeningUIResponder.keyboardWillShowNotification
OpenedUIResponder.keyboardDidShowNotification
ClosingUIResponder.keyboardWillHideNotification
ClosedUIResponder.keyboardDidHideNotification
State changingUIResponder.keyboardWillChangeFrameNotification
State changedUIResponder.keyboardDidChangeFrameNotification

Here is an example program to show "Closed" when keyboard is closed, "Opened" when 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)
                // Here is the point
                .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"
        }
    }
}

// Here is the point
extension UIApplication {
    func closeKeyboard() {
        sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
キーボードを閉じる画像

Note

Do not use UIApplication.shared.keyWindow?.endEditing(true) to close.
UIApplication.shared.keyWindow is deprecated in iOS 13.

References

sendAction(_:to:from:for :)-UIApplication | Apple開発者用ドキュメント

    I released iOS App!

    ToDo App

    Visualize Activity, Data sharing with iCloud, Dark mode supported.

    リリースしたToDoアプリのスクリーンショット

    IP Address bookmark.

    Check and bookamrk IP address of all interfaces with geolocation.

    リリースしたIPアドレス保存アプリのスクリーンショット