I'm moving a UIView up when the keyboard is called, works fine in the simulator but when i run the code on an actual device for whatever reason the UIKeyboardWillShow notification is called twice. I am not using any custom keyboards.
In the viewDidLoad method i call this method.
func registerKeyBoardNotifications(){
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillAppear(notification:)), name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: .UIKeyboardWillHide, object: nil)
}
Then remove these observers in viewWillDisappear.
#objc func keyBoardWillAppear(notification: NSNotification){
if let userInfo = notification.userInfo,
let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue,
let beginFrame = userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue,
beginFrame.isEqual(to: endFrame) == false{
let keyboardSize = endFrame.cgRectValue
self.view.frame.origin.y -= keyboardSize.height - keyboardConstant
signUpButton.isEnabled = false
}
}
the keyboardWillAppear handler is called twice on a physical device but once in the simulator, spent the last 2 days trying to figure this out.
Xcode 9.4.1 swift 4.1
This can happen and there is no documentation that guarantees just one notification.
So you should just deal with it in your code and not substract the keyboard height every time. A smarter solution would be to calculate your view frame depending on keyboard's end frame.
The right approach, as you've been told, is to ask yourself the right question. For example, is it the case that previously the keyboard was not covering my view, but now it is? That is the occasion that should be regarded as "entering".
I have a utility function that works out the geometry based on the notification's userInfo dictionary and the bounds of the view we're concerned with. If the keyboard wasn't within the view's bounds and now it will be, it is entering; if it was within the view's bounds and now it won't be, it is exiting. We return that information, along with the keyboard's frame in the view's bounds coordinates:
enum KeyboardState {
case unknown
case entering
case exiting
}
func keyboardState(for d:[AnyHashable:Any], in v:UIView?)
-> (KeyboardState, CGRect?) {
var rold = d[UIResponder.keyboardFrameBeginUserInfoKey] as! CGRect
var rnew = d[UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
var ks : KeyboardState = .unknown
var newRect : CGRect? = nil
if let v = v {
let co = UIScreen.main.coordinateSpace
rold = co.convert(rold, to:v)
rnew = co.convert(rnew, to:v)
newRect = rnew
if !rold.intersects(v.bounds) && rnew.intersects(v.bounds) {
ks = .entering
}
if rold.intersects(v.bounds) && !rnew.intersects(v.bounds) {
ks = .exiting
}
}
return (ks, newRect)
}
When the keyboard shows, we check whether it is entering, and respond accordingly:
#objc func keyboardShow(_ n:Notification) {
let d = n.userInfo!
let (state, rnew) = keyboardState(for:d, in:myView)
if state == .entering {
// ...
}
}
i seem to have figured out why the UIkeyboardWillShow Notification fires twice on the physical device and not the simulator. It has to do with the keyboard suggestions above the keyboard when you set certain Text Input traits. Any text input trait that causes a suggestion above the keyboard will cause the notification to fire twice instead of once, i'm guessing once for the keyboard itself and again for the suggestion bar above the keyboard. (in my case because there were no suggestions on the simulator it fired once in the simulator, but fired twice on the device because there were suggestions on a real device). This is a weird case thing that doesn't seem to be documented.
One way to deal with this (the route i chose) is to disable all suggestions by setting all Text Input traits to default and the content type of the text field to Username.
The other solution is to account for the second UIkeyboardWillShowNotifcation notification in your code before adjusting the frame of the UIView you're trying move.
Related
Is there a way to check if the user is currently using a custom keyboard? I know how to check all the keyboards but I want to know the exact keyboard that is selected.
Here is how you check which Keyboards are available but how do I know which one the user is currently using?
class func isKeyboardExtensionEnabled() -> Bool {
guard let keyboards = UserDefaults.standard.dictionaryRepresentation()["AppleKeyboards"] as? [String] else {
return false
}
print("the keyboards are \(keyboards)")
for keyboard in keyboards {
if keyboard.contains("KeyboardExtension"){
return true
}
}
return false
}
The why is I have a view that needs to be the same height as the keyboard. I can get the system height pretty easy just making a textfield the responder and dismissing it before it is seen.
let keyboardFrame: NSValue = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue
But for UIKeyboardWillShow notification the height is incorrect causing the height needed for the fixed height view to be incorrect. It is correct after the 2 or 3 call but for custom keyboards I would like to know to expect erroneous values.
But as more to the example if you want to see the incorrect values here is a controller.
import UIKit
import Foundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(notification:)), name: UIWindow.keyboardWillShowNotification, object: nil)
showKeyboard()
}
func showKeyboard(){
let tf = UITextField(frame: .zero)
self.view.addSubview(tf)
tf.becomeFirstResponder()
}
//MARK: Keyboard
#objc func keyboardWillAppear(notification: NSNotification){
//find the extrasafe bottom
if let userInfo = notification.userInfo as? [String: Any],
let keyboardFrame: NSValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue{
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
print("keyboard height is \(keyboardHeight)")
}
}
deinit {
NotificationCenter.default.removeObserver(self, name: UIWindow.keyboardWillShowNotification, object: nil)
}
}
The printed output is keyboard height is 335.0 on the iPhone X. if you install Gboard and make it the default keyboard and run the app you will get a print out of
keyboard height is 75.0
keyboard height is 216.0
keyboard height is 333.0. I would just love to know to expect these junk values.
I have looked around and found this post about moving a view when a keyboard appears. It works great and moves the keyboard anytime I click in a UITextField. The issue is that I have three UITextFields, and the keyboard should only move when it is going to present over a UITextField. I looked at the Apple documentation on this as well, and found some useful information but I am still not getting the desired functionality.
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
var aRect = self.view.frame;
aRect.size.height -= keyboardSize.size.height
if self.view.frame.origin.y == 0{
if aRect.contains(activeField.frame.origin){
self.view.frame.origin.y -= keyboardSize.height
}
}
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
activeField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
activeField = nil
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y != 0{
self.view.frame.origin.y += keyboardSize.height
}
}
}
From the Apple documentation I just took the piece where I create the aRect, and then check if the points intersect with the contains function. I would expect this to then make the view move only when the keyboard were to overlap with a textfield, and keep the view in place otherwise. For some reason that I don't fully understand, this is not the case. The keyboard will move the view in the case where any textfield is clicked (even though for some it shouldn't). I have played around with it a bit now and tried debugging but have been unsuccessful. Any ideas?
EDIT: I did a little debugging and it seems that the aRect.contains(...) is returning true for when all textfields are clicked, but in reality it should not. Is contains the right method to be using?
I followed this way to manage such issue in TableView same way you can manage in your view Here is step by step code:
within viewDidLoad added registerForKeyboardNotifications()
Here is the method
func registerForKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
}
Again define other method :
func keyboardWasShown(aNotification: NSNotification) {
let info = aNotification.userInfo as! [String: AnyObject],
kbSize = (info[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue().size,
contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbSize.height, right: 0)
electricalViewListTableview.contentInset = contentInsets
electricalViewListTableview.scrollIndicatorInsets = contentInsets
// If active text field is hidden by keyboard, scroll it so it's visible
// Your app might not need or want this behavior.
var aRect = self.view.frame
aRect.size.height -= kbSize.height
if let activeTF = activeField {
if !CGRectContainsPoint(aRect, activeTF.frame.origin) {
electricalViewListTableview.scrollRectToVisible(activeTF.frame, animated: true)
}
}
}
Keyboard Hiding Method :
func keyboardWillBeHidden(aNotification: NSNotification) {
let contentInsets = UIEdgeInsetsZero
electricalViewListTableview.contentInset = contentInsets
electricalViewListTableview.scrollIndicatorInsets = contentInsets
}
After this use UITextFieldDelegates method to keep track active textfield :
var activeField: UITextField?
func textFieldDidBeginEditing(textField: UITextField) {
self.activeField = textField
}
func textFieldDidEndEditing(textField: UITextField) {
self.activeField = textField
}
Hope it helps!
You have two main issues with your keyboardWillShow code.
You are using the wrong key to get the keyboard frame. You need UIKeyboardFrameEndUserInfoKey, not UIKeyboardFrameBeginUserInfoKey. You want to know where the keyboard will end up, not where it starts from.
Once you get the keyboard's frame, you need to convert it to local coordinates. It is given to you in screen coordinates.
Your updated code would be:
func keyboardWillShow(notification: NSNotification) {
if let keyboardScreenFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
let keyboardLocalFrame = self.view.convert(keyboardScreenFrame, from: nil)
var aRect = self.view.frame;
aRect.size.height -= keyboardLocalFrame.size.height
if self.view.frame.origin.y == 0 {
if aRect.contains(activeField.frame.origin) {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
}
You also have a big problem with your keyboardWillHide method. Since you keyboardWillShow method always shortens your view's frame, your keyboardWillHide method also needs to always restore the view's frame height.
If I were you, I wouldn't change the view's frame height in either method. Just adjust its origin as needed to make the text field visible.
Try IQKeyboardManager . It automatically manages text fields to make them visible. You just need to add it to your project, and no need to write even one line of code. A piece from it's documentation:
Often while developing an app, We ran into an issues where the iPhone
keyboard slide up and cover the UITextField/UITextView.
IQKeyboardManager allows you to prevent issues of the keyboard sliding
up and cover UITextField/UITextView without needing you to enter any
code and no additional setup required. To use IQKeyboardManager you
simply need to add source files to your project.
EDIT: In addition to Rmaddy's answer, I can say you should consider changing if aRect.contains(activeField.frame.origin) to if !aRect.contains(activeField.frame), because the first check will return true even if the top of your textfield is in the frame of the view, and also, you should be checking if it doesn't contain the frame of your textfield, then change the frame of the view.
And, I'm not totally sure, but, maybe it would be better if you move your activeField = textField code to the textFieldShouldBeginEditing delegate method.
okay so this question is similar to this one , but i followed answer of that question but i didn't worked , so the thing is that i have a Textfield in my view and i want to move it up when keyboard appears this is my code :
Notification observer for keyboard's state
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(LaunchScreenViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
function for getting the keyboard's height
func keyboardWillShow(notification:NSNotification) {
let userInfo:NSDictionary = notification.userInfo!
duration = (notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double)
let keyboardFrame:NSValue = userInfo.valueForKey(UIKeyboardFrameEndUserInfoKey) as! NSValue
let keyboardRectangle = keyboardFrame.CGRectValue()
keyboardHeight = keyboardRectangle.height
}
my animation
func textFieldDidBeginEditing(textField: UITextField) {
self.nextButtonConstraint.constant = keyboardHeight
UIView.animateWithDuration(duration) {
self.nextButton.layoutIfNeeded()
self.emailTextField.layoutIfNeeded()
}
}
as you can see that my animation is on textFieldDidBeginEditing because according to similar question's answer putting it there will solve the problem , but still on first run (when keyboard appears for the first time) my animation is not smooth
I think the solution may be quite simple.
Try to put all you Code inside of this:
DispatchQueue.main.async{
// Your Code here
}
This moves the animation to the main Thread, which should speed it up and avoid the unsmooth animation.
Previously if one presented a keyboard on one's own app one would embed everything in a UIScrollView and adjust the contentInset to keep content from being obscured by the keyboard.
Now with split view multitasking on iOS 9 the keyboard may appear at any moment and stay visible even while the user is no longer interacting with the other app.
Question
Is there an easy way to adapt all view controllers that were not expecting the keyboard to be visible and without start embedding everything in scrollviews?
The secret is to listen to the UIKeyboardWillChangeFrame notification that is triggered whenever the keyboard is shown/hidden from your app or from another app running side by side with yours.
I created this extension to make it easy to start/stop observing those events (I call them in viewWillAppear/Disappear), and easily get the obscuredHeight that is usually used to adjust the bottom contentInset of your table/collection/scrollview.
#objc protocol KeyboardObserver
{
func startObservingKeyboard() // Call this in your controller's viewWillAppear
func stopObservingKeyboard() // Call this in your controller's viewWillDisappear
func keyboardObscuredHeight() -> CGFloat
#objc optional func adjustLayoutForKeyboardObscuredHeight(_ obscuredHeight: CGFloat, keyboardFrame: CGRect, keyboardWillAppearNotification: Notification) // Implement this in your controller and adjust your bottom inset accordingly
}
var _keyboardObscuredHeight:CGFloat = 0.0;
extension UIViewController: KeyboardObserver
{
func startObservingKeyboard()
{
NotificationCenter.default.addObserver(self, selector: #selector(observeKeyboardWillChangeFrameNotification(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
func stopObservingKeyboard()
{
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
func observeKeyboardWillChangeFrameNotification(_ notification: Notification)
{
guard let window = self.view.window else {
return
}
let animationID = "\(self) adjustLayoutForKeyboardObscuredHeight"
UIView.beginAnimations(animationID, context: nil)
UIView.setAnimationCurve(UIViewAnimationCurve(rawValue: (notification.userInfo![UIKeyboardAnimationCurveUserInfoKey]! as AnyObject).intValue)!)
UIView.setAnimationDuration((notification.userInfo![UIKeyboardAnimationCurveUserInfoKey]! as AnyObject).doubleValue)
let keyboardFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue
_keyboardObscuredHeight = window.convert(keyboardFrame!, from: nil).intersection(window.bounds).size.height
let observer = self as KeyboardObserver
observer.adjustLayoutForKeyboardObscuredHeight!(_keyboardObscuredHeight, keyboardFrame: keyboardFrame!, keyboardWillAppearNotification: notification)
UIView.commitAnimations()
}
func keyboardObscuredHeight() -> CGFloat
{
return _keyboardObscuredHeight
}
}
I'm trying to get the height of the iOS keyboard. I've gone through and used the method involving subscribing to a notification such as detailed here:
https://gist.github.com/philipmcdermott/5183731
- (void)viewDidAppear:(BOOL) animated {
[super viewDidAppear:animated];
// Register notification when the keyboard will be show
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
// Register notification when the keyboard will be hide
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardBounds];
// Do something with keyboard height
}
- (void)keyboardWillHide:(NSNotification *)notification {
CGRect keyboardBounds;
[[notification.userInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardBounds];
// Do something with keyboard height
}
This works fine for when the user actually displays the keyboard.
My problem: I have another view, let's call it micView, that may be presented before the keyboard appears. The user may choose to use the microphone before typing. I would like the micView to be the same height as the keyboard, which is why I need the keyboard's height, but I need it before the keyboard was forced to appear. Thus the UIKeyboardWillShowNotification is not reached before I need to read the value of the height.
My question is: how do I get the height of the keyboard through Notifications, or some other method without ever having the keyboard appear.
I considered explicitly forcing the keyboard to appear in viewDidLoad, so that I can set an instance variable to that value, then hiding it and getting rid of the animations for both things. But is that really the only way to do that?
This Swift class provides a turn-key solution that manages all the necessary notifications and initializations, letting you simply call a class method and have returned the keyboard size or height.
Calling from Swift:
let keyboardHeight = KeyboardService.keyboardHeight()
let keyboardSize = KeyboardService.keyboardSize()
Calling from Objective-C:
CGFloat keyboardHeight = [KeyboardService keyboardHeight];
CGRect keyboardSize = [KeyboardService keyboardSize];
If wanting to use this for initial view layout, call this from the viewWillAppear method of a class where you want the keyboard height or size before the keyboard appears. It should not be called in viewDidLoad, as a correct value relies on your views having been laid out. You can then set an autolayout constraint constant with the value returned from the KeyboardService, or use the value in other ways. For instance, you might want to obtain the keyboard height in prepareForSegue to assist in setting a value associated with the contents of a containerView being populated via an embed segue.
Note re safe area, keyboard height, and iPhone X:
The value for keyboard height returns the full height of the keyboard, which on the iPhone X extends to the edge of the screen itself, not just to the safe area inset. Therefore, if setting an auto layout constraint value with the returned value, you should attach that constraint to the superview bottom edge, not to the safe area.
Note re hardware keyboard in Simulator:
When a hardware keyboard is attached, this code will provide the on-screen height of that hardware keyboard, that is, no height. This state does need to be accounted for, of course, as this simulates what will occur if you have a hardware keyboard attached to an actual device. Therefore, your layout that is expecting a keyboard height needs to respond appropriately to a keyboard height of zero.
KeyboardService class:
As usual, if calling from Objective-C, you simply need to import the app's Swift bridging header MyApp-Swift.h in your Objective-C class.
import UIKit
class KeyboardService: NSObject {
static var serviceSingleton = KeyboardService()
var measuredSize: CGRect = CGRect.zero
#objc class func keyboardHeight() -> CGFloat {
let keyboardSize = KeyboardService.keyboardSize()
return keyboardSize.size.height
}
#objc class func keyboardSize() -> CGRect {
return serviceSingleton.measuredSize
}
private func observeKeyboardNotifications() {
let center = NotificationCenter.default
center.addObserver(self, selector: #selector(self.keyboardChange), name: .UIKeyboardDidShow, object: nil)
}
private func observeKeyboard() {
let field = UITextField()
UIApplication.shared.windows.first?.addSubview(field)
field.becomeFirstResponder()
field.resignFirstResponder()
field.removeFromSuperview()
}
#objc private func keyboardChange(_ notification: Notification) {
guard measuredSize == CGRect.zero, let info = notification.userInfo,
let value = info[UIKeyboardFrameEndUserInfoKey] as? NSValue
else { return }
measuredSize = value.cgRectValue
}
override init() {
super.init()
observeKeyboardNotifications()
observeKeyboard()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
Head nod:
The observeKeyboard method here based on the original approach outlined by Peres in the Objective-C answer to this question.
A quick solution that you could use, is the same one used when you want to cache the keyboard (the first time you show it, you get a slight delay...). The library is here. The interesting bits:
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:field];
[field becomeFirstResponder];
[field resignFirstResponder];
[field removeFromSuperview];
So basically is showing it and then hiding it. You could listen for notifications and just get the height without actually seeing it. Bonus: you get to cache it. :)
Looks like this solution did stop working.
I modified it:
adding a callback to know when the notification arrives with the real height,
moving the textfield to another window to avoid showing it, and
setting a timeout for the case when is used in the simulator and the software keyboard is setted up to now show.
Using Swift 4:
import UIKit
public class KeyboardSize {
private static var sharedInstance: KeyboardSize?
private static var measuredSize: CGRect = CGRect.zero
private var addedWindow: UIWindow
private var textfield = UITextField()
private var keyboardHeightKnownCallback: () -> Void = {}
private var simulatorTimeout: Timer?
public class func setup(_ callback: #escaping () -> Void) {
guard measuredSize == CGRect.zero, sharedInstance == nil else {
return
}
sharedInstance = KeyboardSize()
sharedInstance?.keyboardHeightKnownCallback = callback
}
private init() {
addedWindow = UIWindow(frame: UIScreen.main.bounds)
addedWindow.rootViewController = UIViewController()
addedWindow.addSubview(textfield)
observeKeyboardNotifications()
observeKeyboard()
}
public class func height() -> CGFloat {
return measuredSize.height
}
private func observeKeyboardNotifications() {
let center = NotificationCenter.default
center.addObserver(self, selector: #selector(self.keyboardChange), name: UIResponder.keyboardDidShowNotification, object: nil)
}
private func observeKeyboard() {
let currentWindow = UIApplication.shared.keyWindow
addedWindow.makeKeyAndVisible()
textfield.becomeFirstResponder()
currentWindow?.makeKeyAndVisible()
setupTimeoutForSimulator()
}
#objc private func keyboardChange(_ notification: Notification) {
textfield.resignFirstResponder()
textfield.removeFromSuperview()
guard KeyboardSize.measuredSize == CGRect.zero, let info = notification.userInfo,
let value = info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
else { return }
saveKeyboardSize(value.cgRectValue)
}
private func saveKeyboardSize(_ size: CGRect) {
cancelSimulatorTimeout()
KeyboardSize.measuredSize = size
keyboardHeightKnownCallback()
KeyboardSize.sharedInstance = nil
}
private func setupTimeoutForSimulator() {
#if targetEnvironment(simulator)
let timeout = 2.0
simulatorTimeout = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false, block: { (_) in
print(" KeyboardSize")
print(" .keyboardDidShowNotification did not arrive after \(timeout) seconds.")
print(" Please check \"Toogle Software Keyboard\" on the simulator (or press cmd+k in the simulator) and relauch your app.")
print(" A keyboard height of 0 will be used by default.")
self.saveKeyboardSize(CGRect.zero)
})
#endif
}
private func cancelSimulatorTimeout() {
simulatorTimeout?.invalidate()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
Is used in the following way:
let splashVC = some VC to show in the key window during the app setup (just after the didFinishLaunching with options)
window.rootViewController = splashVC
KeyboardSize.setup() { [unowned self] in
let kbHeight = KeyboardSize.height() // != 0 :)
// continue loading another things or presenting the onboarding or the auth
}
For iOS 14.0, I noticed that this solution stopped working on around the 10th call as NotificationCenter stopped broadcasting keyboardChange notification. I was not able to fully figure out why that was happening.
So, I tweaked the solution to make KeyboardSize a singleton and added a method updateKeyboardHeight() as such:
static let shared = KeyboardSize()
/**
Height of keyboard after the class is initialized
*/
private(set) var keyboardHeight: CGFloat = 0.0
private override init() {
super.init()
observeKeyboardNotifications()
observeKeyboard()
}
func updateKeyboardHeight() {
observeKeyboardNotifications()
observeKeyboard()
}
and used it as
KeyboardSize.shared.updateKeyboardHeight()
let heightOfKeyboard = KeyboardSize.shared.keyboardHeight