how to use observer selector function in different ViewControllers - ios

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?

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.

How to determine the keyboard size swift

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.

The keyboard hides textfield, if pickerVew's window opened

I have tableview with two textfields and one Image pickerView button.
If I write something, my textfields are upping, and it's okay.
But, if I choose photo from my imagePicker view and try to write something, I don't see my textfields. Please, help.
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardDidShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardDidHideNotification, object: nil)
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue.size.height {
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
}
}
}
func keyboardWillHide(notification: NSNotification) {
if let userInfo = notification.userInfo {
tableView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0)
}
}

How to make NSNotificationCenter only run when a certain UITextField is selected

I am using NSNotificationCenter to shift the main view frame up when a keyboard is shown.
However, I only want this to work for when one UITextField is selected.
Here is what I have so far:
func getKeyboardHeight(notification: NSNotification) -> CGFloat {
let userInfo = notification.userInfo
let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
return keyboardSize.CGRectValue().height
}
func keyboardWillShow(notification: NSNotification) {
self.view.frame.origin.y -= getKeyboardHeight(notification)
}
func keyboardWillHide(notification: NSNotification) {
self.view.frame.origin.y += getKeyboardHeight(notification)
}
func subscribeToKeyboardNotifications() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
}
func unsubscribeToKeyboardNotifications() {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
}
func subscribeToKeyboardHide() {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}
func unsubscribeToKeyboardHide() {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
In ViewWillAppear()
self.subscribeToKeyboardNotifications()
self.subscribeToKeyboardHide()
In ViewWillDisappear()
self.unsubscribeToKeyboardNotifications()
self.unsubscribeToKeyboardHide()
How do I make the view shift up when I am only selecting one specific UITextField?
Try this
if yourTextfield.isEditing{}
Or this
if yourTextfield.isFirstResponder{}
To check is this is your textfield
You can create the following extension
extension UIView {
/**
Finds the first responder
:returns: the first responder, or nil if nothing found.
*/
private func findFirstResponder() -> UIView? {
if isFirstResponder() { return self }
else {
for view in subviews as! [UIView] {
if let responder = view.findFirstResponder() {
return responder
}
}
return nil
}
}
}
Then call it like this in your keyboardWillShow
let textField = UIApplication.sharedApplication().keyWindow?.findFirstResponder() as? UITextField
You can now use textField currently active.

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