0
votes

I have a ViewController (login view) in xib which has 2 UITextField and 1 UIButton component. The view hierarchy is

 UIView
     -> UIScrollView
         -> UIView (contentView)
             -> UITextField
             -> UITextField
             -> UIButton

I am using autolayout for the view. The UIScrollView has 4 constraints i.e., leading, trailing, top & bottom aligned to its superview (UIViewController view). ContentView has 4 constraints i.e., leading, trailing, top & bottom to its superview (UIScrollView) and width matching UIViewController view.

I have followed the steps as in Apple documentation to scroll up or down when user selects UITextField so that keyboard is not on top of UITextField.

When keyboard is shown scrollview is scrolled up but when keyboard is hidden scrollview does not scroll back. Any help is appreciated.

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func keyboardWillHide(notification: NSNotification) {

        let contentInsets: UIEdgeInsets = UIEdgeInsets.zero
        self.scrollView.contentInset = contentInsets
        self.scrollView.scrollIndicatorInsets = contentInsets
    } 

func keyboardWillShow(notification: NSNotification) {

        if let activeField = self.activeField, let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {

            let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0)

            self.scrollView.contentInset = contentInsets
            self.scrollView.scrollIndicatorInsets = contentInsets

            var aRect = self.view.frame

            aRect.size.height -= keyboardSize.size.height
            if (!aRect.contains(activeField.frame.origin)) {
                self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
            }
        }
    }
2

2 Answers

0
votes

This problem with the keyboard is explained in detail in the apple documentation:

https://developer.apple.com/library/content/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html

Alternatively, try the following code:

func registerForKeyboardNotifications(){
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name:       NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name:    NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func deregisterFromKeyboardNotifications(){
   NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
   NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func keyboardWasShown(notification: NSNotification){
   self.scrollView.isScrollEnabled = true
   var info = notification.userInfo!
   let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
   let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)

   self.scrollView.contentInset = contentInsets
   self.scrollView.scrollIndicatorInsets = contentInsets

   var aRect : CGRect = self.view.frame
   aRect.size.height -= keyboardSize!.height
   if let activeField = self.activeField {
       if (!aRect.contains(activeField.frame.origin)){
           self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
       }
   }
}

func keyboardWillBeHidden(notification: NSNotification){
   var info = notification.userInfo!
   let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
   let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)
   self.scrollView.contentInset = contentInsets
   self.scrollView.scrollIndicatorInsets = contentInsets
   self.view.endEditing(true)
   self.scrollView.isScrollEnabled = false
}

func textFieldDidBeginEditing(_ textField: UITextField){
   activeField = textField
}

func textFieldDidEndEditing(_ textField: UITextField){
   activeField = nil
}
0
votes

The scrollView contentInset.top was not 0.0 hence i was facing the problem. After changing contentInset.top properly scrollView set to original position after keyboard was hidden.

func keyboardWillShow(notification: NSNotification) {

        self.scrollView.isScrollEnabled = true

        var info = notification.userInfo!
        let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
        let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(self.scrollView.contentInset.top, 0.0, keyboardSize!.height, 0.0)

        self.scrollView.contentInset = contentInsets
        self.scrollView.scrollIndicatorInsets = contentInsets

        var aRect : CGRect = self.view.frame
        aRect.size.height -= keyboardSize!.height
        if let activeField = self.activeField {
            if (!aRect.contains(activeField.frame.origin)){
                self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
            }
        }
    }