Created
April 9, 2018 09:31
-
-
Save brownsoo/854412d3845fbb41d96c497371f64b70 to your computer and use it in GitHub Desktop.
Responsive to keyboard frame in iOS
This file contains hidden or 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
// in UIViewController | |
func setupHideKeypadWhenTappedAround() { | |
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) | |
tap.cancelsTouchesInView = false | |
view.addGestureRecognizer(tap) | |
// responsive keyboard frame | |
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillChange), | |
name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) | |
} | |
@objc | |
private func handleTap(sender: UITapGestureRecognizer) { | |
// hide keyboard | |
view.endEditing(true) | |
} | |
@objc | |
private func handleKeyboardWillChange(sender: Notification) { | |
// parsing notification | |
let n = KeyboardNotification(sender) | |
let keyboardFrame = n.frameEndForView(view: self.view) | |
let duration = n.animationDuration | |
let curve = n.animationCurve | |
var frame: CGRect = self.view.frame | |
frame.size = CGSize(width: frame.size.width, height: keyboardFrame.minY) | |
willChangeViewFrame(frame, duration: duration, option: UIViewAnimationOptions(rawValue: UInt(curve << 16))) | |
} | |
/// Notify a view of UIViewController will be changes its frame | |
func willChangeViewFrame(_ to: CGRect, duration: Double, option: UIViewAnimationOptions) { | |
} | |
/// | |
/// Helper struct to parse Notification of UIKeyboardWillChangeFrame | |
import UIKit | |
// https://gist.github.com/kristopherjohnson/13d5f18b0d56b0ea9242 | |
/// Wrapper for the NSNotification userInfo values associated with a keyboard notification. | |
/// | |
/// It provides properties that retrieve userInfo dictionary values with these keys: | |
/// | |
/// - UIKeyboardFrameBeginUserInfoKey | |
/// - UIKeyboardFrameEndUserInfoKey | |
/// - UIKeyboardAnimationDurationUserInfoKey | |
/// - UIKeyboardAnimationCurveUserInfoKey | |
public struct KeyboardNotification { | |
let notification: Notification | |
let userInfo: Dictionary<String, Any> | |
/// Initializer | |
/// | |
/// :param: notification Keyboard-related notification | |
public init(_ notification: Notification) { | |
self.notification = notification | |
if let userInfo = notification.userInfo { | |
self.userInfo = userInfo as! Dictionary | |
} else { | |
self.userInfo = Dictionary() | |
} | |
} | |
/// Start frame of the keyboard in screen coordinates | |
public var screenFrameBegin: CGRect { | |
if let value = userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue { | |
return value.cgRectValue | |
} else { | |
return CGRect.zero | |
} | |
} | |
/// End frame of the keyboard in screen coordinates | |
public var screenFrameEnd: CGRect { | |
if let value = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue { | |
return value.cgRectValue | |
} else { | |
return CGRect.zero | |
} | |
} | |
/// keyboard animation duration | |
public var animationDuration: Double { | |
if let number = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber { | |
return number.doubleValue | |
} else { | |
return 0.25 | |
} | |
} | |
/// Keyboard animation curve | |
/// | |
/// Note that the value returned by this method may not correspond to a | |
/// UIViewAnimationCurve enum value. For example, in iOS 7 and iOS 8, | |
/// this returns the value 7. | |
public var animationCurve: Int { | |
if let number = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber { | |
return number.intValue | |
} | |
return UIViewAnimationCurve.easeInOut.rawValue | |
} | |
/// Start frame of the keyboard in coordinates of specified view | |
/// | |
/// :param: view UIView to whose coordinate system the frame will be converted | |
/// :returns: frame rectangle in view's coordinate system | |
public func frameBeginForView(view: UIView) -> CGRect { | |
return view.convert(screenFrameBegin, from: view.window) | |
} | |
/// End frame of the keyboard in coordinates of specified view | |
/// | |
/// :param: view UIView to whose coordinate system the frame will be converted | |
/// :returns: frame rectangle in view's coordinate system | |
public func frameEndForView(view: UIView) -> CGRect { | |
return view.convert(screenFrameEnd, from: view.window) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment