Created
June 20, 2017 06:56
-
-
Save afshin-hoseini/04925be00b650ea46a96f3459e6e85b6 to your computer and use it in GitHub Desktop.
Swift keyboard frame change behavior controller
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
// | |
// 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