How to determine the keyboard size swift - ios

I'm trying to move up a UIButton when the keyboard is shown. So when the keyboard is shown, the UIButton moves up 20px above the keyboard at the same time the keyboard animation is shown so it look like the button is connected to the keyboard. So I need to determine the size of the keyboard so I can apply that to the button event.
Here is my code:
#objc func keyboardWillChange(notification: Notification) {
if notification.name == UIResponder.keyboardWillShowNotification || notification.name == UIResponder.keyboardWillChangeFrameNotification {
nextBtn.frame.origin.y = view.frame.maxY - 300
} else {
nextBtn.frame.origin.y = 0
}
}
I have a few problems with my code:
class Start_EmailVC: UIViewController, UITextFieldDelegate {
var checkValid = CheckValid()
#IBOutlet weak var nextBtn: UIButton!
#IBOutlet weak var emailTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
//Next Button Auth
nextBtn.alpha = 0.5
nextBtn.isEnabled = false
hideIt()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardShown), name: UIResponder.keyboardWillShowNotification, object: nil);
}
#objc func keyboardShown(notification: NSNotification) {
let info = notification.userInfo!
let keyboardFrame: CGRect = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
print("keyboardFrame: \(keyboardFrame)")
}
func hideIt() {
//Listen For Keyboard Events
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
deinit {
//Stop Listening for keyboard hide/show events
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
#objc func keyboardWillChange(notification: Notification) {
if notification.name == UIResponder.keyboardWillShowNotification || notification.name == UIResponder.keyboardWillChangeFrameNotification {
nextBtn.frame.origin.y = view.frame.maxY - 300
} else {
nextBtn.frame.origin.y = 0
}
}}
The button does push up but not the same time as the keyboard and it just doesn't look good.

Related

View is getting shifted every time I re-tap textfield

so I have a small app where I choose an image, get it into an image view
and I have 2 textfield to insert a funny phrase
(Meme editor app)
my problem is since the bottom textfield is covered when the keyboard is shown I had to shift the view upwards every time the keyboard is shown for the bottom texfield and I succeed in doing that, what goes wrong is that every time I re-tap the beginning or the end of an existing text in the text filed the view shifts up again in undesirable behavior
here is a small GIF that shows what happens exactly
here is my code so far:
Function to get Kyboard height:
func getKeyboardHeight(_ notification:Notification) -> CGFloat {
let userInfo = notification.userInfo
let keyboardSize = userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue // of CGRect
return keyboardSize.cgRectValue.height
}
Function to shift the view up in the condition that bottom textfield is what the user taps
#objc func keyboardWillShow(_ notification:Notification) {
if bottomTextField.isFirstResponder{
view.frame.origin.y -= getKeyboardHeight(notification)
}
}
Function to return the view to its normal position when the user finishes editing the bottom text field
#objc func keyboardWillHide(_ notification:Notification) {
view.frame.origin.y = 0
}
Functions to add and remove observers of keyboard notifications
func subscribeToKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
}
func subscribekeyboardWillHide() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func unsubscribeFromKeyboardNotifications() {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}
func unsubscribekeyboardWillHide() {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
and where I call them
override func viewWillAppear(_ animated: Bool) {
super .viewWillAppear(true)
cameraButton.isEnabled = UIImagePickerController.isSourceTypeAvailable(.camera)
subscribeToKeyboardNotifications()
subscribekeyboardWillHide()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
unsubscribeFromKeyboardNotifications()
unsubscribekeyboardWillHide()
}
if you could be kind to provide a simple explanation for your solution I would appreciate it
This is what I do while managing keyboard. It causes no problems.
Declare in your UIViewController class
private let notificationCenter = NotificationCenter.default
then in
override func viewDidLoad() {
super.viewDidLoad()
notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
This is the adjust for keyboard function
#objc private func adjustForKeyboard(notification: Notification) {
guard let userInfo = notification.userInfo else { return }
guard let keyboardScreenEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return }
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
if notification.name == UIResponder.keyboardWillHideNotification {
scrollView.contentInset = UIEdgeInsets.zero
} else {
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0)
}
scrollView.scrollIndicatorInsets = scrollView.contentInset
}
Deinit here -
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(true)
notificationCenter.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
notificationCenter.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
Every time you change the cursor location, UIResponder.keyboardWillShowNotification notification triggered, thats why every time you tap the textfield it moves up one keyboard height more.
You can use UIResponder.keyboardDidShowNotification notification instead of UIResponder.keyboardWillShowNotification. This one is not triggered when cursor location changes.

move view up when only keyboard cover textfield

I am trying to build an input screen for the iPhone in swift. The screen has a number of input fields. Most of them on the top of the screen, but three fields are at the bottom. When the user tries to edit the text on the bottom of the screen, the keyboard will pop up and it will cover the screen. I found a simple solution to move the screen up when this happens, but the result is that the screen always moves up and the fields on top of the screen move out of reach when the user tries to edit those.
for example : I want form txt1 to txt4 the view does not go up.
Is there a way to have the screen only move when the bottom fields are edited?
I have used this code I found here:
override func viewDidLoad() {
txt1.delegate = self
txt2.delegate = self
txt3.delegate = self
txt4.delegate = self
txt5.delegate = self
txt6.delegate = self
txt7.delegate = self
txt8.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
#objc func keyboardWillHide(notification: NSNotification) {
if view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
**
I did this function to start show keyboard while I start editing on textfields:
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool{
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
but here it's going for all the textfield that I have and its the same problem.
how can I make it for specific textfield?

Getting correct value of keyboard height when using custom keyboards - SWIFT 3

So I have a UIButton which sits at the bottom of the UIView until the keyboard appears then the bottom constraint is updated to the keyboard height.
This works fine with the iOS default keyboard, but when using a custom keyboard like swiftKey the bottom constraint is still that of the iOS Keyboard height.
I have noticed that a custom keyboard sets off three notifications instead of one. So this may be the issue but how can I use the correct value ?
#IBOutlet weak var fieldBottomConstant: NSLayoutConstraint!
var keyboardShowing = false
var keyboardHeight: CGFloat = 0.0
func keyboardWillShow(_ n:Notification) {
self.keyboardShowing = true
if let keyboardSize = (n.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
// fieldBottomConstant.constant = keyboardSize.height
keyboardHeight = keyboardSize.height
}
fieldBottomConstant.constant = keyboardHeight
}
func keyboardWillHide(_ n:Notification) {
self.keyboardShowing = false
fieldBottomConstant.constant = 0
}
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(AddViewController.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(AddViewController.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(AddViewController.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(AddViewController.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(AddViewController.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardDidChangeFrame, object: nil)
}
UPDATE
I have added some more notifications to watch for any changes, and the constraints change to the custom keyboard height after rotating the devices however still do not use the custom keyboard height when the keyboard is first loaded.
The answer was to use
UIKeyboardFrameEndUserInfoKey
You should listen NSNotification.Name.UIKeyboardWillChangeFrame

how to use observer selector function in different ViewControllers

I have login and registration forms in my application. When user tap any textField I calculate the difference in height of keyboard and textField and scroll my view if needed.
For this I've added two observers in loginVC:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
func keyboardWillShow(notification: NSNotification) {
println("keyb show")
keyboardIsShown = true
keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height
calculateAnimationValue()
}
func keyboardWillHide(notification: NSNotification) {
println("keyb hide")
keyboardIsShown = false
animateViewMoving(false, moveValue: animationValue)
animationValue = 0
}
func textFieldDidBeginEditing(textField: UITextField) {
pressedTextField = textField
textField.becomeFirstResponder()
if keyboardIsShown {
calculateAnimationValue()
}
}
func calculateAnimationValue() {
if keyboardHeight != nil {
var windowHeight = self.view.frame.height
var textFieldY = pressedTextField.frame.origin.y
var windowWithoutKeyboard = windowHeight - keyboardHeight - 44
if textFieldY > windowWithoutKeyboard {
if animationValue < (textFieldY - windowWithoutKeyboard) {
animationValue = animationValue + textFieldY - windowWithoutKeyboard
animateViewMoving(true, moveValue: animationValue)
}
}
}
println(animationValue)
}
func animateViewMoving (up: Bool, moveValue: CGFloat){
var movementDuration: NSTimeInterval = 0.3
var movement:CGFloat = (up ? -moveValue : moveValue)
UIView.beginAnimations("animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration)
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
But I want to do the same in registrationVC.
How can I use keyboardWillShow, keyboardWillHide in another VC?
I've tried to add the same observers but then the application fires these methods in loginVC not in registrationVC.
Can someone help me?
UPDATE: ------------------------
class LogInViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
println("keyb show")
}
func keyboardWillHide(notification: NSNotification) {
println("keyb hide")
}
}
class RegistrationViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
println("keyb show2")
}
func keyboardWillHide(notification: NSNotification) {
println("keyb hide2")
}
deinit {
println("deinit")
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
}
If I touch textField's on loginVC and segue to registerVC it works well and prints "keyb show2".
But if didn't touch textField's on loginVC and segue to registerVC and touch textField it prints "keyb show". Which is called from previous controller. What I am doing wrong?

Adjust View for keyboard appears when switching UITextField (Swift)

I have two UIView's , the Main one and one which will move up when the keyboard appears (Second UIView has two textfields). I've managed to do this with the following code:
LoginViewController.swift :
override func viewDidLoad() {
super.viewDidLoad()
self.originalCenter = self.contentView.center;
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardDidShow:", name: UIKeyboardDidShowNotification, object: nil)
}
func keyboardDidShow(notification: NSNotification)
{
UIView.animateWithDuration(1.0, animations: {
self.contentView.center = CGPointMake(self.originalCenter.x, self.originalCenter.y - 40);
})
}
My big problems is that because the movement of the UIView depends on the keyboard notification, when the user taps one TextField it moves up as it should, but when he taps the second one the view moves down automatically. What Im I doing wrong?
This is what is happening: Keyboard Error Gif
This question was answered over here , but I need the solution for Swift language.
Create an instance variable and check whether the keyboard was activated or not:
class ViewController: UIViewController, UITextFieldDelegate {
var _keyboardActivated: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
registerForKeyboardNotifications()
}
override func viewWillDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UIKeyboardDidShowNotification,
object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self,
name: UIKeyboardWillHideNotification,
object: nil)
}
func registerForKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "keyboardWillShow:",
name: UIKeyboardWillShowNotification,
object: nil)
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "keyboardWillBeHidden:",
name: UIKeyboardWillHideNotification,
object: nil)
}
func keyboardWillShow(notification: NSNotification) {
if (!_keyboardActivated) {
// do stuff
}
_keyboardActivated = true
}
func keyboardWillBeHidden(notification: NSNotification) {
_keyboardActivated = false
}
}
Set delegate of your textfield and implement the below methods
func textFieldDidBeginEditing(textField: UITextField) {
animateViewMoving(true, moveValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
animateViewMoving(false, moveValue: 100)
}
func animateViewMoving (up:Bool, moveValue :CGFloat){
var movementDuration:NSTimeInterval = 0.3
var movement:CGFloat = ( up ? -moveValue : moveValue)
UIView.beginAnimations( "animateView", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(movementDuration )
self.view.frame = CGRectOffset(self.view.frame, 0, movement)
UIView.commitAnimations()
}
Reference: http://www.jogendra.com/2015/01/uitextfield-move-up-when-keyboard.html

Resources