Skip to content

Instantly share code, notes, and snippets.

@sam-moshenko
Last active June 17, 2017 15:54
Show Gist options
  • Save sam-moshenko/064e03c1d0ef150de4aaf60473d844ae to your computer and use it in GitHub Desktop.
Save sam-moshenko/064e03c1d0ef150de4aaf60473d844ae to your computer and use it in GitHub Desktop.
BaseViewController for iOS Swift to handle keyboard overlapping important views and easier translations between view controllers(IMHO)
//
// BaseVC.swift
//
// Created by Simon on 4/23/17.
// Copyright © 2017 Simon. All rights reserved.
//
import UIKit
/*
Paste here your format which you use
to identify StoryboardID for your VCs(View Controllers)
I recomend using StoryboardID which are the same as
naming of the class it uses
Paste '%@' where you have a real name of VC
For example if you have VCs named as:
TMLoginVC, TMRegisterVC, TMMenuVC
then you should use "TM%@VC" as your VCFormat
*/
let VCFormat = "%@VC"
/*
List here all VCs' real names which you want to show from code
this name will be used with the VCFormat to constract a StoryboardID
*/
enum VCs: String {
case Menu = "Menu"
}
class BaseVC: UIViewController, UITextFieldDelegate, UITextViewDelegate {
private var currentTextField: UIView?
/*
Assgin all textFields' and textViews' delegates
to viewController that inherits from the BaseVC
*/
/*
Connect this constraint to a content view's top
to move all your content up when a keyboard appears
*/
@IBOutlet weak var contentTopSpaceConstraint: NSLayoutConstraint?
private var initialTopSpace: CGFloat?
private var keyboardNotification: NSNotification?
override func viewDidLoad() {
super.viewDidLoad()
self.initialTopSpace = self.contentTopSpaceConstraint?.constant
let tap = UITapGestureRecognizer.init(target: self, action: #selector(resignCurrentTextField))
view.addGestureRecognizer(tap)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func getViewController(viewController: VCs) -> UIViewController {
let viewControllerName = String(format: VCFormat, viewController.rawValue)
return (storyboard?.instantiateViewController(withIdentifier: viewControllerName))!
}
func animateLayoutWithDuration(duration: Double, options: UIViewAnimationOptions) {
UIView.animate(withDuration: duration, delay: 0.0, options: options, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
// MARK: Keyboard handling
@IBAction func resignCurrentTextField(sender: NSObject) {
if currentTextField != nil {
currentTextField?.resignFirstResponder()
}
}
func registerForKeyboardEvents() {
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification),
name: .UIKeyboardWillHide, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification),
name: .UIKeyboardWillShow, object: nil)
}
func handleKeyboardNotification(notification: NSNotification) {
let keyboardRect = view.convert((notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue, from: nil)
let curve = (notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! NSNumber).uintValue
let duration = (notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
let animationCurveOption = curve << 16
let textFieldFrame = view.convert((self.currentTextField?.frame)!, from: currentTextField?.superview)
if notification.name == .UIKeyboardWillShow {
let difference = textFieldFrame.maxY - keyboardRect.origin.y
if difference > 0 {
contentTopSpaceConstraint?.constant = self.initialTopSpace! - difference - 8.0
}
self.keyboardNotification = notification
} else {
contentTopSpaceConstraint?.constant = self.initialTopSpace!
self.keyboardNotification = nil
}
animateLayoutWithDuration(duration: duration, options: UIViewAnimationOptions(rawValue: animationCurveOption))
}
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
currentTextField = textField
if keyboardNotification != nil {
handleKeyboardNotification(notification: keyboardNotification!)
}
return true
}
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
currentTextField = textView
if keyboardNotification != nil {
handleKeyboardNotification(notification: keyboardNotification!)
}
return true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment