Skip to content

Instantly share code, notes, and snippets.

@RyogaK
Last active August 25, 2016 08:23
Show Gist options
  • Save RyogaK/1458bd43a2c0ea7d88aa9480fe9ed549 to your computer and use it in GitHub Desktop.
Save RyogaK/1458bd43a2c0ea7d88aa9480fe9ed549 to your computer and use it in GitHub Desktop.
//
// UIViewController+ScrollWhenKeyboardAppear.swift
// LIFE
//
// Created by Ryoga Kitagawa on 8/8/16.
// Copyright © 2016 Givery Inc. All rights reserved.
//
import Foundation
extension UIViewController {
func startKeyboardAvoiding() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UIViewController.scrollTextFieldWhehKeybordShown(_:)), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UIViewController.restoreScrollTextField(_:)), name: UIKeyboardWillHideNotification, object: nil)
}
func endKeyboardAvoidance() {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
@objc func scrollTextFieldWhehKeybordShown(notification: NSNotification) {
guard let textField = self.view.currentFirstResponder() as? UIView,
scrollView = textField.findSuperView(UIScrollView.self),
userInfo = notification.userInfo,
keyboardFrame = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue,
animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey]?.doubleValue
else { return }
let margin = keyboardMarginForResponderView(textField)
let maxOffset = scrollView.contentSize.height - scrollView.bounds.height + keyboardFrame.height
let origOffset = scrollView.contentOffset
scrollView.contentInset = UIEdgeInsetsZero
scrollView.scrollIndicatorInsets = UIEdgeInsetsZero
let convertedKeyboardFrame = scrollView.convertRect(keyboardFrame, fromView: nil)
let convertedTextFieldFrame = textField.convertRect(textField.bounds, toView: scrollView)
let diffOfOffsetY = convertedTextFieldFrame.maxY - convertedKeyboardFrame.minY + margin
if diffOfOffsetY > 0 {
UIView.animateWithDuration(animationDuration) {
let offsetY = min(diffOfOffsetY + origOffset.y, maxOffset)
let insetsY = max(diffOfOffsetY + origOffset.y - maxOffset, 0)
let contentInsets = UIEdgeInsetsMake(0, 0, insetsY, 0)
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
scrollView.contentOffset = CGPointMake(0, offsetY)
}
}
}
@objc func restoreScrollTextField(notification: NSNotification) {
guard let textField = self.view.currentFirstResponder() as? UIView,
let scrollView = textField.findSuperView(UIScrollView.self)
else { return }
scrollView.contentInset = UIEdgeInsetsZero
scrollView.scrollIndicatorInsets = UIEdgeInsetsZero
}
func keyboardMarginForResponderView(view: UIView) -> CGFloat {
return 8
}
}
private extension UIView {
func currentFirstResponder() -> UIResponder? {
if self.isFirstResponder() {
return self
}
for view in self.subviews {
if let responder = view.currentFirstResponder() {
return responder
}
}
return nil
}
func insertTextToCurrentField(text: String) {
guard let field = self.currentFirstResponder() as? UIKeyInput else { return }
field.insertText(text)
}
func findSuperView<T>(ofType: T.Type) -> T? {
if let s = self.superview {
switch s {
case let s as T:
return s
default:
return s.findSuperView(ofType)
}
}
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment