-2

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?

Community
  • 1
  • 1
mufc
  • 695
  • 3
  • 16
  • 31

3 Answers3

1

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!

Shobhakar Tiwari
  • 7,862
  • 4
  • 36
  • 71
1

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.

Community
  • 1
  • 1
Fahri Azimov
  • 11,470
  • 2
  • 21
  • 29
  • 1
    The question is about the posted code. This "answer" makes no attempt to explain why the posted code is not working. – rmaddy Nov 27 '16 at 17:22
  • Yeah, I was going to answer the question as well, didn't have that much time. I'll add the answer. – Fahri Azimov Nov 28 '16 at 03:26
1

You have two main issues with your keyboardWillShow code.

  1. 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.
  2. 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.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • This is still not doing it for me. Still occurs that keyboard will shift entire view regardless of what text field is being clicked. And to clarify, isn't adjusting the frames origin exactly what Im already doing? how else do i modify the frames origin if not by doing self.view.frame.origin.y? Sorry, fairly new to swift and iOS so questions may seem a little beginner. – mufc Nov 27 '16 at 20:07