Created
April 27, 2016 20:46
-
-
Save paulononaka/64a9273e1de03a426322042dc74f8552 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
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