SwiftUI: How to dismiss the keyboard by tap on NavigationLink?

Hi,


I have TextField and a list with buttons NavigationLink.

When i tap on NavigationLink i need to dismiss the keyboard, how?



Thanks in advance.


import SwiftUI

struct ContentView: View {
   let array = ["John","Lena","Steve","Chris","Catalina"]

        @State private var searchText = ""

        var body: some View {


            NavigationView{
              List{
                  TextField("Type your search",text: $searchText)
                      .textFieldStyle(RoundedBorderTextFieldStyle())

                  ForEach(array.filter{$0.hasPrefix(searchText) || searchText == ""}, id:\.self){names in
                    NavigationLink(destination:keyboardDissmis(text: names)){
                        Text(names)
                      }
                  }
              }
              .navigationBarTitle(Text("Search"))
          }
            .gesture(DragGesture().onChanged{_ in UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to:nil, from:nil, for:nil)})
           
    }
}

func keyboardDissmis(text:String)->Text{
    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to:nil, from:nil, for:nil)
   
    return Text(text)
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Replies

One way to do this is by adding this extension to `UIView`:


extension UIView {
    open override func touchesBegan(_ touches: Set, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        UIApplication.shared.windows
            .first { $0.isKeyWindow }?
            .endEditing(true)
    }
}
Works in Xcode 12 beta
Code Block swift
import SwiftUI
struct ContentView: View {
...
var body: some View {
NavigationView {
...
}
.onTapGesture {
hideKeyboard()
}
}
}
#if canImport(UIKit)
extension View {
    func hideKeyboard() {
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}
#endif


This does work, however...
It seems to have a side effect of making a segmented picker inside the nav view unresponsive. (Oddly, a Toggle control does still work.)
Bug or feature I'm not sure.

I've tried the onTapGesture at different levels and also tried onDisappear, none of which resolved the issue.

xcode 12.4/iOS 14.1
  • I am struggling with this issue that persists in xcode 13.2/iOS 15.

Add a Comment

You can create an extension of View with the hideKeyboard like sprykly said.

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

Then in your view:

struct MyViewCell: View {
    @State var navigate = false
    
    var body: some View {
        ZStack {
          
            NavigationLink(destination: DestinyView()), isActive: $navigate) {
                EmptyView()
            }
            .hidden()
            .buttonStyle(PlainButtonStyle())
           
            VStack {
                ContentOfView()
               
            }.onTapGesture {
                hideKeyboard()
                navigate = true
            }
        } 
    }
}

Used in SwiftUI1