Created
February 3, 2020 04:57
-
-
Save danielpunkass/4f26d9df5c38758e82c88944e14700ab to your computer and use it in GitHub Desktop.
This file contains 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 characters
// | |
// 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 | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment