Skip to content

Instantly share code, notes, and snippets.

@cenkbilgen
Last active March 29, 2021 18:41
Show Gist options
  • Save cenkbilgen/d12ed1abbbc25edb1e21a8d2480f99b9 to your computer and use it in GitHub Desktop.
Save cenkbilgen/d12ed1abbbc25edb1e21a8d2480f99b9 to your computer and use it in GitHub Desktop.
SwiftUI EnvironmentObject for Keyboard Changes
import SwiftUI
import Combine
#if os(iOS)
import UIKit.UIResponder
#endif
class KeyboardObserver: ObservableObject {
struct State: Equatable {
let frame: CGRect
let isLocal: Bool // on multitasking iPad apps, all visible apps notified
}
@Published var state = State(frame: .zero, isLocal: true)
#if os(iOS)
private let didShowPublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardDidShowNotification)
private let didHidePublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardDidHideNotification)
private let didChangeFramePublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardDidChangeFrameNotification)
private var cancellables: Set<AnyCancellable> = []
#endif
init() {
#if os(iOS)
didShowPublisher
.merge(with: didChangeFramePublisher)
.receive(on: RunLoop.main)
.tryMap { notification -> State in
guard let frame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect,
let isLocal = notification.userInfo?[UIResponder.keyboardIsLocalUserInfoKey] as? Bool else {
throw CocoaError(.keyValueValidation)
}
return State(frame: frame, isLocal: isLocal)
}
.replaceError(with: State(frame: .zero, isLocal: true))
.removeDuplicates()
.setFailureType(to: Never.self)
.assign(to: \.state, on: self)
.store(in: &cancellables)
didHidePublisher
.ignoreOutput()
.receive(on: RunLoop.main)
.sink { _ in
self.state = State(frame: .zero, isLocal: true)
}
.store(in: &cancellables)
#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment