Skip to content

Instantly share code, notes, and snippets.

@afshin-hoseini
Created June 20, 2017 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afshin-hoseini/04925be00b650ea46a96f3459e6e85b6 to your computer and use it in GitHub Desktop.
Save afshin-hoseini/04925be00b650ea46a96f3459e6e85b6 to your computer and use it in GitHub Desktop.
Swift keyboard frame change behavior controller
//
// KeyboardBehaviorController.swift
// Spot
//
// Created by Afshin on 6/20/17.
// Copyright © 2017 AFE. All rights reserved.
//
import Foundation
import UIKit
class KeyboardBehaviorController {
weak var appDelegate: AppDelegate?
var closeBtn: UIButton?
var closeBtn_constraints = [NSLayoutConstraint]()
var isRegistered = false
init(appDelegate: AppDelegate) {
self.appDelegate = appDelegate
registerKeyboardListener()
}
private func setupCloseBtn() {
self.closeBtn = UIButton()
self.closeBtn!.backgroundColor = UIColor(ARGB: 0x55000000)
self.closeBtn!.layer.masksToBounds = true
self.closeBtn!.layer.cornerRadius = 20
self.closeBtn!.setImage(#imageLiteral(resourceName: "KeyboardClose").scale(toSize: CGSize(width: 30, height: 30))!, for: .normal)
self.closeBtn!.contentMode = .center
self.closeBtn!.addTarget(self, action: #selector(btnKeyboardCloseClicked), for: .touchUpInside)
}
func registerKeyboardListener() {
if appDelegate?.window != nil && !isRegistered {
setupCloseBtn()
NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardFrameWillChange(_:)), name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
}
}
@objc private func onKeyboardFrameWillChange(_ notification : Notification) {
let duration = notification.userInfo?["UIKeyboardAnimationDurationUserInfoKey"]
let keyboardEndRect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as! CGRect
let keyboardBeginRect = notification.userInfo?["UIKeyboardFrameBeginUserInfoKey"] as! CGRect
let isLocalUser = (notification.userInfo?["UIKeyboardIsLocalUserInfoKey"] as! Int) > 0
guard isLocalUser else { return }
//Current responder
var responder = UIResponder.currentFirst()
//The viewcontroller that is shown modally or top most view controller of current navigation controller
var topMostVc : UIViewController? = nil
//Finds the view topMostVc
while let next = responder?.next {
if let next = next as? UIViewController , (next.parent == nil || next.parent is UINavigationController) {
topMostVc = next
break
}
responder = next
}
if let vc = topMostVc, vc is KeyboardChangeResponsive {
let isClosed = (UIScreen.main.bounds.height <= keyboardEndRect.origin.y)
let isOpening = !isClosed
//Attaches the close button to view if not attached before
if isOpening && self.closeBtn_constraints.count == 0 {
vc.view.addSubview(self.closeBtn!)
self.closeBtn?.isHidden = false
self.closeBtn?.layer.opacity = 0
vc.view.layoutIfNeeded()
self.closeBtn?.translatesAutoresizingMaskIntoConstraints = false
self.closeBtn_constraints = [
self.closeBtn!.bottomAnchor.constraint(equalTo: vc.view.bottomAnchor, constant: -20),
self.closeBtn!.rightAnchor.constraint(equalTo: vc.view.rightAnchor, constant: -20),
self.closeBtn!.widthAnchor.constraint(equalToConstant: 40),
self.closeBtn!.heightAnchor.constraint(equalToConstant: 40)
]
NSLayoutConstraint.activate(self.closeBtn_constraints)
}
//Animates the view's height
UIView.animate(withDuration: duration as! TimeInterval, animations: {
if (vc as! KeyboardChangeResponsive).keyboardBehavior == .resize {
vc.view.frame.size.height = vc.view.frame.size.height + (keyboardEndRect.origin.y - keyboardBeginRect.origin.y)
}
vc.view.layoutIfNeeded()
}) {
c in
self.animateCloseBtn(visibility: isClosed)
}
}
}
private func animateCloseBtn(visibility: Bool) {
if visibility {
UIView.animate(withDuration: 0.3, animations: {
self.closeBtn!.layer.opacity = 0
}){ c in
//Removes the close button from view and make it ready for next attachment
self.closeBtn_constraints.removeAll()
self.closeBtn?.superview?.removeConstraints(self.closeBtn_constraints)
self.closeBtn!.removeFromSuperview()
}
}
else {
UIView.animate(withDuration: 0.3, animations: {
self.closeBtn!.layer.opacity = 1
})
}
}
@objc private func btnKeyboardCloseClicked() {
appDelegate?.window?.endEditing(true)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment