@@ -127,7 +127,6 @@ struct MicrobolusView: View {
127127 }
128128
129129 @ObservedObject var viewModel : ViewModel
130- @ObservedObject private var keyboard = KeyboardResponder ( )
131130
132131 init ( viewModel: ViewModel ) {
133132 self . viewModel = viewModel
@@ -202,9 +201,7 @@ struct MicrobolusView: View {
202201 VStack ( alignment: . leading) {
203202 Text ( " If the override's target range starts at the given value or more " ) . font ( . caption)
204203 HStack {
205- TextField ( " 0 " , text: $viewModel. lowerBound, onEditingChanged: { changed in
206-
207- } ) { self . dismissKeyboard ( ) }
204+ TextField ( " 0 " , text: $viewModel. lowerBound)
208205 . keyboardType ( . decimalPad)
209206 . multilineTextAlignment ( . trailing)
210207
@@ -228,7 +225,7 @@ struct MicrobolusView: View {
228225
229226 }
230227 . navigationBarTitle ( " Microboluses " )
231- . padding ( . bottom , keyboard . currentHeight )
228+ . modifier ( AdaptsToSoftwareKeyboard ( ) )
232229 }
233230}
234231
@@ -259,39 +256,33 @@ struct MicrobolusView_Previews: PreviewProvider {
259256
260257// MARK: - Helpers
261258
262- extension UIApplication {
263- func endEditing( ) {
264- sendAction ( #selector( UIResponder . resignFirstResponder) , to: nil , from: nil , for: nil )
265- }
266- }
259+ struct AdaptsToSoftwareKeyboard : ViewModifier {
260+ @State var currentHeight : CGFloat = 0
267261
268- extension View {
269- func dismissKeyboard( ) {
270- UIApplication . shared. endEditing ( )
262+ func body( content: Content ) -> some View {
263+ content
264+ . padding ( . bottom, currentHeight) . animation ( . easeOut( duration: 0.25 ) )
265+ . edgesIgnoringSafeArea ( currentHeight == 0 ? Edge . Set ( ) : . bottom)
266+ . onAppear ( perform: subscribeToKeyboardChanges)
271267 }
272- }
273268
274- final class KeyboardResponder : ObservableObject {
275- private var notificationCenter : NotificationCenter
276- @Published private( set) var currentHeight : CGFloat = 0
269+ private let keyboardHeightOnOpening = NotificationCenter . default
270+ . publisher ( for: UIResponder . keyboardWillShowNotification)
271+ . map { $0. userInfo![ UIResponder . keyboardFrameEndUserInfoKey] as! CGRect }
272+ . map { $0. height }
277273
278- init ( center: NotificationCenter = . default) {
279- notificationCenter = center
280- notificationCenter. addObserver ( self , selector: #selector( keyBoardWillShow ( notification: ) ) , name: UIResponder . keyboardWillShowNotification, object: nil )
281- notificationCenter. addObserver ( self , selector: #selector( keyBoardWillHide ( notification: ) ) , name: UIResponder . keyboardWillHideNotification, object: nil )
282- }
283274
284- deinit {
285- notificationCenter . removeObserver ( self )
286- }
275+ private let keyboardHeightOnHiding = NotificationCenter . default
276+ . publisher ( for : UIResponder . keyboardWillHideNotification )
277+ . map { _ in return CGFloat ( 0 ) }
287278
288- @objc func keyBoardWillShow( notification: Notification ) {
289- if let keyboardSize = ( notification. userInfo ? [ UIResponder . keyboardFrameEndUserInfoKey] as? NSValue ) ? . cgRectValue {
290- currentHeight = keyboardSize. height
279+ private func subscribeToKeyboardChanges( ) {
280+ _ = Publishers . Merge ( keyboardHeightOnOpening, keyboardHeightOnHiding)
281+ . subscribe ( on: DispatchQueue . main)
282+ . sink { height in
283+ if self . currentHeight == 0 || height == 0 {
284+ self . currentHeight = height
285+ }
291286 }
292287 }
293-
294- @objc func keyBoardWillHide( notification: Notification ) {
295- currentHeight = 0
296- }
297288}
0 commit comments