Created
February 3, 2020 04:57
-
-
Save danielpunkass/4f26d9df5c38758e82c88944e14700ab to your computer and use it in GitHub Desktop.
Revisions
-
danielpunkass created this gist
Feb 3, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,104 @@ // // UIView+RSKeyboardLayoutGuide.swift // RSTouchUIKit // // Created by Daniel Jalkut on 12/23/18. // import UIKit // Extends UIView to expose a keyboardLayoutGuide property that can be used to tie a view controller's content // to so that it will automatically move out of the way when the keyboard appears. extension UIView { func layoutGuide(withIdentifier identifier: String) -> UILayoutGuide? { // Should only ever be one with a matching identifier return self.layoutGuides.filter { $0.identifier == identifier }.first } @objc(rsKeyboardLayoutGuide) public var keyboardLayoutGuide: UILayoutGuide { get { let keyboardGuideIdentifier = "com.red-sweater.layoutguide.keyboard" if let existingGuide = self.layoutGuide(withIdentifier: keyboardGuideIdentifier) { return existingGuide } else { let newGuide = UILayoutGuide() newGuide.identifier = keyboardGuideIdentifier self.addLayoutGuide(newGuide) let heightConstraint = newGuide.heightAnchor.constraint(equalToConstant: 0) heightConstraint.isActive = true newGuide.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true // Subscribe to notifications of keyboard size change, so we can adapt our // guide to match. NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification, object: nil, queue: nil) { [weak self] note in guard let existingSelf = self, let noteInfo = note.userInfo, let keyboardFrame = noteInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, let superview = existingSelf.superview else { return } let keyboardFrameInSuperview = superview.convert(keyboardFrame, from: nil) let ourFrameInSuperview = superview.convert(existingSelf.frame, from: existingSelf) // Special case - if the keyboard is floating we disregard its height. I don't know how // to strictly tell if it's floating but when it is floating it seems to represent sometimes // as having a 0 width or awkward 36 height. Let's just assume a keyboard width less than // half the main screen width is floating. let screenWidth = UIScreen.main.bounds.size.width let isFloatingKeyboard = keyboardFrameInSuperview.width < (screenWidth / 2) // The height anchor constant should be our view's max Y minus the keyboad frame's // min Y, which is effectively the top edge of the keyboard. let newKeyboardHeight = isFloatingKeyboard ? 0 : max(0.0, ourFrameInSuperview.maxY - keyboardFrameInSuperview.minY) // Animate if we have pertinent animation info if let animationDuration = noteInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval { let animationCurve: UIView.AnimationCurve if let curveValue = noteInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int, let validCurve = UIView.AnimationCurve(rawValue: curveValue) { animationCurve = validCurve } else { animationCurve = .easeInOut } // Map from curve value to animation options let animationOptions: UIView.AnimationOptions switch animationCurve { case .easeInOut: animationOptions = .curveEaseInOut case .easeIn: animationOptions = .curveEaseIn case .easeOut: animationOptions = .curveEaseOut case .linear: animationOptions = .curveLinear default: animationOptions = .curveEaseInOut } UIView.animate(withDuration: animationDuration, delay: 0, options: animationOptions, animations: { heightConstraint.constant = newKeyboardHeight }, completion: nil) } else { heightConstraint.constant = newKeyboardHeight } } return newGuide } } } }