I want to know if the keyboard is present when the button is pressed. How would I do this? I have tried but I don't have any luck. Thanks.
I want to know if the keyboard is present when the button is pressed. How would I do this? I have tried but I don't have any luck. Thanks.
Using this protocol, KeyboardReadable, you can conform to any View and get keyboard updates from it.
KeyboardReadable protocol:
import Combine
import UIKit
/// Publisher to read keyboard changes.
protocol KeyboardReadable {
var keyboardPublisher: AnyPublisher<Bool, Never> { get }
}
extension KeyboardReadable {
var keyboardPublisher: AnyPublisher<Bool, Never> {
Publishers.Merge(
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { _ in true },
NotificationCenter.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in false }
)
.eraseToAnyPublisher()
}
}
It works by using Combine and creating a publisher so we can receive the keyboard notifications.
With an example view of how it can be applied:
struct ContentView: View, KeyboardReadable {
@State private var text: String = ""
@State private var isKeyboardVisible = false
var body: some View {
TextField("Text", text: $text)
.onReceive(keyboardPublisher) { newIsKeyboardVisible in
print("Is keyboard visible? ", newIsKeyboardVisible)
isKeyboardVisible = newIsKeyboardVisible
}
}
}
You can now read from the isKeyboardVisible variable to know if the keyboard is visible.
When the TextField is active with the keyboard showing, the following prints:
Is keyboard visible? true
When the keyboard is then hidden upon hitting return, the following prints instead:
Is keyboard visible? false
You can use keyboardWillShowNotification/keyboardWillHideNotification to update as soon as they keyboard starts to appear or disappear, and the keyboardDidShowNotification/keyboardDidHideNotification variants to update after the keyboard has appeared or disappeared. I prefer the will variant because the updates are instant for when the keyboard shows.
You can use the focused(_:) view modifier and @FocusState property wrapper to know whether a text field is editing, and also change the editing state.
@State private var text: String = ""
@FocusState private var isTextFieldFocused: Bool
var body: some View {
VStack {
TextField("hello", text: $text)
.focused($isTextFieldFocused)
if isTextFieldFocused {
Button("Keyboard is up!") {
isTextFieldFocused = false
}
}
}
}
My little improvement @George's answer.
Implement publisher right inside the View protocol
extension View {
var keyboardPublisher: AnyPublisher<Bool, Never> {
Publishers
.Merge(
NotificationCenter
.default
.publisher(for: UIResponder.keyboardWillShowNotification)
.map { _ in true },
NotificationCenter
.default
.publisher(for: UIResponder.keyboardWillHideNotification)
.map { _ in false })
.debounce(for: .seconds(0.1), scheduler: RunLoop.main)
.eraseToAnyPublisher()
}
}
I also added debounce operator in order to prevent true - false toggle when you have multiple TextFields and user moves between them.
Use in any View
struct SwiftUIView: View {
@State var isKeyboardPresented = false
@State var firstTextField = ""
@State var secondTextField = ""
var body: some View {
VStack {
TextField("First textField", text: $firstTextField)
TextField("Second textField", text: $secondTextField)
}
.onReceive(keyboardPublisher) { value in
isKeyboardPresented = value
}
}
}