Search code examples
iosswiftswiftuikeyboardtextfield

iPhone keyboard dissapear and appear again when switching between fields with onTapGesture(hideKeyboard)


I have this code in Swift (iOS 16+) and I have a login screen into my app, where the user needs to enter an email and password.

I also have a .onTapGesture method on the GeometryReader { ... } wrapping everything together. I want the user to be able to dismiss the keyboard when tapping away from the text field.

But when the user enters an email and then wants to enter a password, the keyboard disappear and then appears again. How can I do that so the keyboard stays open (same expecting result as without the onTapGesture).

Here is my code

struct LoginView: View {
    
    @Environment(\.horizontalSizeClass) var horizontalSizeClass
    
    @State var email: String = ""
    @State var password: String = ""
    
    private let hapticFeedbackService = HapticFeedbackService()
    
    var body: some View {
        GeometryReader { screenGeometry in
            let screenHeight = screenGeometry.size.height
            
            ZStack {
                Color.black.background.ignoresSafeArea(.all)
                
                VStack {
                    WelcomeTextView(welcomeText: "sign_in_to")
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .padding(.top, screenHeight * 0.02)
                    
                    VStack {
                        InputField(
                            text: $email,
                            placeholder: "enter_email",
                            isSecure: false
                        )
                        .padding(.bottom, 15)
                        
                        InputField(
                            text: $password,
                            placeholder: "enter_password",
                            isSecure: true,
                            trailingIcon: Image("Lock")
                        )
                    }
                    
                    Button(action: {
                        hapticFeedbackService.triggerHapticFeedback()
                        print("Button pressed")
                    }) {
                        Text(LocalizedStringKey("forgot_your_password"))
                            .font(.thinnerSmallTitle)
                    }
                    .padding(.top, 5)
                    .padding(.trailing, 5)
                    .frame(maxWidth: .infinity, alignment: .trailing)
                    
                    LargeButton(
                        text: "sign_in",
                        textColor: Color.black,
                        backgroundColor: Color.white
                    ) {
                        hapticFeedbackService.triggerHapticFeedback()
                        print("Button pressed")
                    }
                    .padding(.top, 40)
                    
                    Text(LocalizedStringKey("other_login_options"))
                        .font(.mediumText)
                        .padding(.top, 10)
                    
                    HStack {
                        SSOButton(type: .Apple, action: {
                            hapticFeedbackService.triggerHapticFeedback()
                            print("Button pressed")
                        })
                        .padding(.trailing, 5)
                        
                        SSOButton(type: .Google, action: {
                            hapticFeedbackService.triggerHapticFeedback()
                            print("Button pressed")
                        })
                        .padding(.leading, 5)
                    }
                    .padding(.top, 10)
                    
                    HStack {
                        Text(LocalizedStringKey("dont_have_account"))
                            .font(.mediumText)
                            .foregroundColor(Color.black)
                        
                        Button(action: {
                            hapticFeedbackService.triggerHapticFeedback()
                            print("Button pressed")
                        }) {
                            Text(LocalizedStringKey("dont_have_account_sign_up"))
                                .font(.smallTitle)
                                .foregroundColor(Color.black)
                        }
                    }
                    .padding(.top, 25)
                    
                    Spacer()
                }
                .paddedFrame(
                    screenSize: screenGeometry.size,
                    horizontalSizeClass: horizontalSizeClass
                )
            }
        }
        .ignoresSafeArea(.keyboard)
        .onTapGesture { self.hideKeyboard() }
    }
    
    private func hideKeyboard() {
        // UIApplication.shared.keyWindow?.endEditing(true) - Depricated
        
        UIApplication.shared.sendAction(
            #selector(UIResponder.resignFirstResponder),
            to: nil,
            from: nil,
            for: nil
        )
    }
}

Thank you.


Solution

  • One another solution is like

    on your ZStack

    ZStack {
           Color.yellow.frame(maxWidth: .infinity, maxHeight: .infinity).onTapGesture {
                            hideKeyboard()
                        }
    

    And at the bottom no need to give tap geture to your entire ZStack

    ZStack {
    //Your code
     }
            .ignoresSafeArea(.keyboard)
            .onTapGesture { self.hideKeyboard() }
    
                
    

    It should work.