Dismissing the Keyboard (iOS 15)

One of the issues encountered when creating a TextField (such as for a search box), is that the on-screen keyboard isn’t dismissed automatically when the user clicks outside the TextField.

In the CWC+ iOS Databases course, Module 6, Lesson 5, Chris shows us how to dismiss the keyboard using pre-iOS 15 code, re:

...
VStack {
    ...
}
.onTapGesture {
    // Resign first responder
    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}

Being on the primary VStack means that the code is executed anywhere the user taps on the screen (because the VStack fills the screen). However, I feel that this code is confusing and that there must be a better way of doing it today.

So I hunted around for a modern solution, and the key is using the new @FocusState property wrapper, and then it’s as simple as adding

import SwiftUI

struct RecipeListView: View {
    ...
    @FocusState private var inFocus: Bool
    ...

    var body: some View {
        NavigationView {
            VStack (alignment: .leading) {
                ...
                SearchBarView(
                    filterText: $filterBy
                )
                    .padding([.bottom, .trailing])
                    .focused($inFocus)
                ...
            }
            ...
            .onTapGesture {
                inFocus = false
            }
        }
    }
}

When the user taps elsewhere on the screen (in the VStack), the .onTapGesture sets the inFocus property to false which tells iOS that they’re outside the TextField and so the keyboard is automatically dismissed.

And, when the user taps back inside the TextField (which is within our SearchBarView sub-view), the keyboard will pop up automatically as normal.