Skip to content

Instantly share code, notes, and snippets.

@paulononaka
Created April 27, 2016 20:46
Show Gist options
  • Save paulononaka/64a9273e1de03a426322042dc74f8552 to your computer and use it in GitHub Desktop.
Save paulononaka/64a9273e1de03a426322042dc74f8552 to your computer and use it in GitHub Desktop.
import UIKit
class SwiftKeyboardAvoiderHelper: NSObject, UITextFieldDelegate {
private let durationTime: Double! = 0.2
private var viewController: UIViewController!
private var originalFrame: CGRect!
private var necessaryShift: CGFloat! = 0
var shift: CGFloat!
var target: UIView!
var fields: [(textField: UITextField, originalDelegate: UITextFieldDelegate?)]! = []
init(viewController: UIViewController, shift: CGFloat = 10) {
super.init()
self.viewController = viewController
self.shift = shift
}
// ---------------------------------------------------------------------------
// MARK: UITextField delegates
// ---------------------------------------------------------------------------
func textFieldShouldReturn(textField: UITextField) -> Bool {
if let delegate = originalDelegate(textField), textFieldShouldReturn = delegate.textFieldShouldReturn {
textFieldShouldReturn(textField)
}
let textFields = fields.map { $0.textField }
if let index = textFields.indexOf(textField) {
let nextIndex = index.successor()
if (nextIndex < textFields.count) {
let nextField = textFields[nextIndex]
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
}
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
if let delegate = originalDelegate(textField), textFieldDidBeginEditing = delegate.textFieldDidBeginEditing {
textFieldDidBeginEditing(textField)
}
self.target = textField
}
// ---------------------------------------------------------------------------
// MARK: Keyboard observers
// ---------------------------------------------------------------------------
func register() {
let textFields: [UITextField] = getTextFields(self.viewController.view)
self.target = textFields.first
self.fields = getDelegates(textFields)
let keyboardDidShowSelector = #selector(KeyboardAvoider.keyboardDidShow(_:))
let keyboardDidHideSelector = #selector(KeyboardAvoider.keyboardDidHide(_:))
defaultCenter().addObserver(self, selector: keyboardDidShowSelector, name: UIKeyboardDidShowNotification, object: nil)
defaultCenter().addObserver(self, selector: keyboardDidHideSelector, name: UIKeyboardDidHideNotification, object: nil)
}
func deregister() {
defaultCenter().removeObserver(self)
}
@objc private func keyboardDidShow(notification: NSNotification) {
self.returnViewToOriginalPosition()
if let target = self.target {
let info: NSDictionary! = notification.userInfo
let keyboardDimension: CGSize! = info.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue.size
let screenDimension = UIScreen.mainScreen().bounds
let realPosition = target.convertRect(target.bounds, toView: nil)
let endingViewFrameY = realPosition.origin.y + realPosition.size.height
let beginingViewFrameY = screenDimension.size.height - keyboardDimension.height
if endingViewFrameY + self.shift > beginingViewFrameY {
self.necessaryShift = (endingViewFrameY - beginingViewFrameY + self.shift) * -1
}
if self.necessaryShift != 0 {
UIView.animateWithDuration(self.durationTime, animations: {
let frame = self.viewController.view.frame
self.originalFrame = frame
self.viewController.view.frame = CGRectMake(frame.origin.x, frame.origin.y + self.necessaryShift, frame.size.width, frame.size.height)
})
}
}
}
@objc private func keyboardDidHide(notification: NSNotification) {
self.returnViewToOriginalPosition()
}
// ---------------------------------------------------------------------------
// MARK: Helpers
// ---------------------------------------------------------------------------
private func defaultCenter() -> NSNotificationCenter {
return NSNotificationCenter.defaultCenter()
}
private func returnViewToOriginalPosition() {
if self.necessaryShift != 0 {
UIView.animateWithDuration(self.durationTime, animations: {
let viewToAdjust: UIView! = self.viewController.view
viewToAdjust?.frame = self.originalFrame
})
}
self.necessaryShift = 0
}
private func originalDelegate(textField: UITextField) -> UITextFieldDelegate? {
let t = fields.filter { t, d in return t == textField }
return t.first?.originalDelegate
}
private func getTextFields(v: UIView) -> [UITextField] {
var textFields = [UITextField]()
for subview in v.subviews {
textFields += getTextFields(subview)
if subview is UITextField {
textFields.append(subview as! UITextField)
}
}
return textFields
}
private func getDelegates(textFields: [UITextField]) -> [(textField: UITextField, originalDelegate: UITextFieldDelegate?)] {
var fields: [(textField: UITextField, originalDelegate: UITextFieldDelegate?)] = []
for t in textFields {
if let delegate = t.delegate {
fields.append((textField: t, originalDelegate: delegate))
}
t.delegate = self
t.returnKeyType = UIReturnKeyType.Continue
}
let lastTextField = textFields[textFields.count-1]
lastTextField.returnKeyType = UIReturnKeyType.Done
return fields
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment