简体   繁体   English

TextField SwiftUI 关闭键盘

[英]TextField SwiftUI Dismiss Keyboard

How can I dismiss the keyboard after the user clicks outside the TextField using SwiftUI?如何在用户使用 SwiftUI 在TextField外部单击后关闭键盘?

I created a TextField using SwiftUI, but I couldn't find any solution for dismissing the keyboard if the user clicks outside the TextField .我使用 SwiftUI 创建了一个TextField ,但如果用户在TextField外部单击,我找不到任何关闭键盘的解决方案。 I took a look at all attributes of TextField and also the SwiftUI TextField documentation and I couldn't find anything related with dismissing keyboard.我查看了TextField的所有属性以及SwiftUI TextField 文档,但找不到与关闭键盘相关的任何内容。

This is my view's code:这是我的视图代码:

struct InputView: View {
    @State var inputValue : String = ""
    var body: some View {

        VStack(spacing: 10) {
            TextField("$", text: $inputValue)
                .keyboardType(.decimalPad)
        }
    }
}

This can be done with a view modifier.这可以通过视图修饰符来完成。

Code代码

public extension View {
    func dismissKeyboardOnTap() -> some View {
        modifier(DismissKeyboardOnTap())
    }
}

public struct DismissKeyboardOnTap: ViewModifier {
    public func body(content: Content) -> some View {
        #if os(macOS)
        return content
        #else
        return content.gesture(tapGesture)
        #endif
    }

    private var tapGesture: some Gesture {
        TapGesture().onEnded(endEditing)
    }

    private func endEditing() {
        UIApplication.shared.connectedScenes
            .filter {$0.activationState == .foregroundActive}
            .map {$0 as? UIWindowScene}
            .compactMap({$0})
            .first?.windows
            .filter {$0.isKeyWindow}
            .first?.endEditing(true)
    }
}

Usage用法

backgroundView()
   .dismissKeyboardOnTap()

Check out the demo here: https://github.com/youjinp/SwiftUIKit在此处查看演示: https : //github.com/youjinp/SwiftUIKit

here is the solution using DragGesture it's working.这是使用 DragGesture 的解决方案。

struct ContentView: View {
    @State var text: String = ""
    var body: some View {
        VStack {
            TextField("My Text", text: $text)
                .keyboardType(.decimalPad)
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
        .edgesIgnoringSafeArea(.all)
        .gesture(
            TapGesture()
                .onEnded { _ in
                    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
            }
        )
    }
}

Add tap gesture to most outer view and call extension method inside tap gesture closure.将点击手势添加到大多数外部视图,并在点击手势闭包内调用扩展方法。

struct InputView: View {
    @State var inputValue : String = ""
    var body: some View {
        
        VStack(spacing: 10) {
            TextField("$", text: $inputValue)
                .keyboardType(.decimalPad)
        } .onTapGesture(perform: {
            self.endTextEditing()
        })
    }
}

extension View {
    func endTextEditing() {
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
                                        to: nil, from: nil, for: nil)
    }
}
TextField("Phone Number", text: $no)
    .keyboardType(.numbersAndPunctuation)
    .padding()
    .background(Color("4"))
    .clipShape(RoundedRectangle(cornerRadius: 10))
    .offset(y:-self.value).animation(.spring()).onAppear() {
         NotificationCenter.default.addObserver(forName:UIResponder.keyboardWillShowNotification, object: nil, queue: .main){ (notif)in
        let value  = notif.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
            let height = value.height
            self.value = height


        }
        NotificationCenter.default.addObserver(forName:UIResponder.keyboardWillHideNotification, object: nil, queue: .main){ (notification)in
        self.value = 0
    }
}

In SwiftUI 3 @FocusState wrapper can be used to remove or switch focus from editable fields.在 SwiftUI 3 中, @FocusState包装器可用于从可编辑字段中移除或切换焦点。 When the focus is removed from field, keyboard dismisses.当焦点从字段中移开时,键盘会消失。 So in your case it is just a matter of giving space and gesture to the surrounding space of TextView .因此,在您的情况下,这只是为TextView的周围空间提供空间和手势的问题。

struct ContentView: View {
    @State var inputValue : String = ""
    @FocusState private var inputIsFocused: Bool
    var body: some View {
        VStack(spacing: 10) {
            TextField("$", text: $inputValue)
                .keyboardType(.decimalPad)
                .border(Color.green)
                .focused($inputIsFocused)
            
        }
        .frame(maxHeight: .infinity) // If input is supposed to be in the center
        .background(.yellow)
        .onTapGesture {
            inputIsFocused = false
        }
    }
}  

But we can do more interesting things with @FocusState .但是我们可以用@FocusState做更多有趣的事情。 How about switching from field to field in a form.如何在表单中从一个字段切换到另一个字段。 And if you tap away, keyboard also dismisses.如果您轻按,键盘也会关闭。

struct ContentView: View {
    enum Field {
        case firstName
        case lastName
        case emailAddress
    }

    @State private var firstName = ""
    @State private var lastName = ""
    @State private var emailAddress = ""
    @FocusState private var focusedField: Field?

    var body: some View {
        ZStack {
            VStack {
                TextField("Enter first name", text: $firstName)
                    .focused($focusedField, equals: .firstName)
                    .textContentType(.givenName)
                    .submitLabel(.next)
                
                TextField("Enter last name", text: $lastName)
                    .focused($focusedField, equals: .lastName)
                    .textContentType(.familyName)
                    .submitLabel(.next)
                
                TextField("Enter email address", text: $emailAddress)
                    .focused($focusedField, equals: .emailAddress)
                    .textContentType(.emailAddress)
                    .submitLabel(.join)
            }
            .onSubmit {
                switch focusedField {
                case .firstName:
                    focusedField = .lastName
                case .lastName:
                    focusedField = .emailAddress
                default:
                    print("Creating account…")
                }
            }
        }
        .textFieldStyle(.roundedBorder)
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .contentShape(Rectangle()) // So ZStack becomes clickable
        .onTapGesture {
            focusedField = nil
        }
    }
}
 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM