1

I'm currently developing an application using SwiftUI.

When I use a onTapGesture at Form in NavigationView, navigation of Picker the inside doesn't work.

It works but only when I long-press a link like a LongPressGesture.

If I don't use onTapGesture, the navigation of Picker works, as usual, But in that case, I can not close a keyboard when I use TextField choosing numberPad as keyboardType...

How could I solve this problem?


Here is a code:

OnTapGestureTest.swift

import SwiftUI

struct OnTapGestureTest: View{
    
    @State var inputNo:String = ""
    @State var selectNo:Int = 0
    
    var body: some View {
        NavigationView{
            Form{
                TextField("InputNo", text: $inputNo)
                    .keyboardType(.numberPad)
                
                Picker(selection:$selectNo, label: Text("SelectNo")){
                    Text("0").tag(0)
                    Text("1").tag(1)
                    Text("2").tag(2)
                    Text("3").tag(3)
                    Text("4").tag(4)
                    Text("5").tag(5)
                    
                }
            }
            .onTapGesture {
                UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
            }
        }
    }
}

UPDATED

I tried to solve my question by referencing here.

*I want to close keyboard only on Tap outside (without handling drags) in iOS 13.0

SceneDelegate.swift

...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
...
        let tapGesture = UITapGestureRecognizer(target: window, action:#selector(UIView.endEditing))
        tapGesture.requiresExclusiveTouchType = false
        tapGesture.cancelsTouchesInView = false
        tapGesture.delegate = self 
        window?.addGestureRecognizer(tapGesture)
    }
...

But it still doesn't work well... Do I need to do some more things? misunderstand the answer?


Xcode: Version 12.0.1

iOS: 13.0

Tio
  • 944
  • 3
  • 15
  • 35

1 Answers1

2

You could add the tap gesture globally, with the help of UIWindow:

extension UIApplication {
    
    func addTapGestureRecognizer() {
        guard let window = windows.first else { return }
        let tapGesture = UITapGestureRecognizer(target: window, action: #selector(UIView.endEditing))
        tapGesture.requiresExclusiveTouchType = false
        tapGesture.cancelsTouchesInView = false
        tapGesture.delegate = self
        window.addGestureRecognizer(tapGesture)
    }
}


extension UIApplication: UIGestureRecognizerDelegate {
    
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true 
    }
}

In your main: (The idea: as soon as your app launches, this tapGesture is added to the window)

@main
struct YourApp: App {
    
    ...
    
    var body: some Scene {
        WindowGroup {
            //Your initial view
                .onAppear(perform: UIApplication.shared.addTapGestureRecognizer)
        }
    }
}

This is especially convenient since you don't have to take care of hiding the keyboard ever again inside your views and it's not blocking any of your controls.

Note

This code is from Here

Also, I saw iOS13 - for non SwiftUI Cycle, this would be the equivalent: Here

Kai Zheng
  • 6,640
  • 7
  • 43
  • 66
  • Thank you for your help, I tried to do a couple of solutions by referencing this link `https://stackoverflow.com/a/60010955/8700044` like my updated question. Do I need to add some code in my struct `OnTapGestureTest.swift`? – Tio Nov 26 '20 at 19:24
  • Did you remove the tapGesture from the `Form`? – Kai Zheng Nov 26 '20 at 19:33
  • No I didn't change anything in the `Form`. – Tio Nov 26 '20 at 19:36
  • Otherwise, you could try to use my solution for SwiftUI Cycle. Just add the `onAppear` to your initial view inside your `SceneDelegate`. Should be the same. It's working fine for me. – Kai Zheng Nov 26 '20 at 19:36
  • You should get rid of the tapGesture inside your `OnTapGestureTest`. – Kai Zheng Nov 26 '20 at 19:37
  • 1
    I removed `tapGesture`, and then it works well, Thank you so much for your support! – Tio Nov 26 '20 at 19:47
  • Perfect! I am happy to help. – Kai Zheng Nov 26 '20 at 19:49