How to hide keyboard when using SwiftUI?

2020-01-27 02:53发布

How to hide keyboard using SwiftUI for below cases?

Case 1

I have TextField and I need to hide the keyboard when the user clicks the return button.

Case 2

I have TextField and I need to hide the keyboard when the user taps outside.

How I can do this using SwiftUI?

Note:

I have not asked a question regarding UITextField. I want to do it by using SwifUI(TextField).

13条回答
爷的心禁止访问
2楼-- · 2020-01-27 03:31

You can force the first responder to resign by sending an action to the shared application:

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

Now you can use this method to close the keyboard whenever you desire:

struct ContentView : View {
    @State private var name: String = ""

    var body: some View {
        VStack {
            Text("Hello \(name)")
            TextField("Name...", text: self.$name) {
                // Called when the user tap the return button
                // see `onCommit` on TextField initializer.
                UIApplication.shared.endEditing()
            }
        }
    }
}

If you want to close the keyboard with a tap out, you can create a full screen white view with a tap action, that will trigger the endEditing(_:):

struct Background<Content: View>: View {
    private var content: Content

    init(@ViewBuilder content: @escaping () -> Content) {
        self.content = content()
    }

    var body: some View {
        Color.white
        .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
        .overlay(content)
    }
}

struct ContentView : View {
    @State private var name: String = ""

    var body: some View {
        Background {
            VStack {
                Text("Hello \(self.name)")
                TextField("Name...", text: self.$name) {
                    self.endEditing()
                }
            }
        }.onTapGesture {
            self.endEditing()
        }
    }

    private func endEditing() {
        UIApplication.shared.endEditing()
    }
}
查看更多
Anthone
3楼-- · 2020-01-27 03:36

Seems like the endEditing solution is the only one like @rraphael pointed out.
The cleanest example I've seen so far is this:

extension View {
    func endEditing(_ force: Bool) {
        UIApplication.shared.keyWindow?.endEditing(force)
    }
}

and then using it in the onCommit:

查看更多
爷的心禁止访问
4楼-- · 2020-01-27 03:36

This method allows you to hide the keyboard on spacers!

First add this function (Credit Given To: Casper Zandbergen, from SwiftUI can't tap in Spacer of HStack)

extension Spacer {
    public func onTapGesture(count: Int = 1, perform action: @escaping () -> Void) -> some View {
        ZStack {
            Color.black.opacity(0.001).onTapGesture(count: count, perform: action)
            self
        }
    }
}

Next add the following 2 functions (Credit Given To: rraphael, from this question)

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

The function below would be added to your View class, just refer to the top answer here from rraphael for more details.

private func endEditing() {
   UIApplication.shared.endEditing()
}

Finally, you can now simply call...

Spacer().onTapGesture {
    self.endEditing()
}

This will make any spacer area close the keyboard now. No need for a big white background view anymore!

You could hypothetically apply this technique of extension to any controls you need to support TapGestures that do not currently do so and call the onTapGesture function in combination with self.endEditing() to close the keyboard in any situation you desire.

查看更多
神经病院院长
5楼-- · 2020-01-27 03:39

My solution how to hide software keyboard when users tap outside. You need to use contentShape with onTapGesture to detect the entire View container.

You can add it to SceneDelegate.swift

window.rootViewController = UIHostingController(rootView:
    contentView.contentShape(Rectangle()).onTapGesture { window.endEditing(true) })
)

or call endEditing inside any View and anywhere

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

without contentShape

VStack {
...
}
.onTapGesture {
    self.endEditing()
}

with contentShape

VStack {
...
}
.contentShape(Rectangle())
.onTapGesture {
    self.endEditing()
}
查看更多
叛逆
6楼-- · 2020-01-27 03:40

add this modifier to the view you want to detect user taps

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

        }
查看更多
戒情不戒烟
7楼-- · 2020-01-27 03:41

I prefer using the .onLongPressGesture(minimumDuration: 0, which does not cause the keyboard to blink when another TextView is activated (side effect of .onTapGesture). The hide keyboard code can be a reusable function.

.onTapGesture(count: 2){} // UI is unresponsive without this line. Why?
.onLongPressGesture(minimumDuration: 0, maximumDistance: 0, pressing: nil, perform: hide_keyboard)

func hide_keyboard()
{
    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
查看更多
登录 后发表回答