1

I would like to customize the scroll-offset when showing the keyboard. As you can see in the GIF, the Textfields are quite close to the keyboard and I would like to have a custom position. The "Name" textfield should have 50px more distance and the "Loan Title" textfield should just scroll to the bottom of my UIScrollView.

screen recording

To be able to scroll past the keyboard I'm changing the UIScrollView insets. Strangely iOS automatically scrolls to the firstResponder textfield (see GIF).

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    // get the Keyboard size
    let userInfo = notification.userInfo!
    let keyboardEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

    // update edge insets for scrollview
    self.mainScrollView.scrollIndicatorInsets.bottom = keyboardEndFrame.height - self.view.layoutMargins.bottom
    self.mainScrollView.contentInset.bottom = keyboardEndFrame.height - self.view.layoutMargins.bottom
}

I already tried to use the UITextfieldDelegate method: textFieldDidBeginEditing(_ textField: UITextField)
I also tried to use the Apple way described here: https://stackoverflow.com/a/28813720/7421005

None of these ways let me customize the automatic scroll position. In fact it kind of overrides every attempt. Does anyone know a way to workaround this?

alexkaessner
  • 1,966
  • 1
  • 14
  • 39

2 Answers2

0

You can prevent your view controller from automatically scrolling by setting automaticallyAdjustsScrollviewInsets to false as described here.

Implementing keyboard avoidance is also pretty straight forward. You can see how to do it here.

I don't believe there is any way to keep the automatic positioning and apply your own custom offset. You could experiment with making text field contained in another larger view and making that larger view the first responder, but that would be a hack at best.

InkGolem
  • 2,662
  • 1
  • 15
  • 22
  • `automaticallyAdjustsScrollviewInsets`is deprecated since iOS 11! However I could find a solution by myself, thanks. – alexkaessner Feb 13 '20 at 15:30
0

I found a solution by myself. The problem was that the automatic scroll (animation) was interfering with my scrollRectToVisible call. Putting this in async fixed the problem.

It now looks similar to this:

override func viewDidLoad() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    // get the Keyboard size
    let userInfo = notification.userInfo!
    let keyboardEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

    // update edge insets for scrollview
    self.mainScrollView.scrollIndicatorInsets.bottom = keyboardEndFrame.height - self.view.layoutMargins.bottom
    self.mainScrollView.contentInset.bottom = keyboardEndFrame.height - self.view.layoutMargins.bottom

    var frame = CGRect.zero

    if nameTextField.isFirstResponder {
        frame = CGRect(x: nameTextField.frame.origin.x, y: nameTextField.frame.origin.y + 50, width: nameTextField.frame.size.width, height: nameTextField.frame.size.height)
    }
    if titleTextField.isFirstResponder {
        frame = CGRect(x: titleTextField.frame.origin.x, y: titleTextField.frame.origin.y + titleShortcutsCollectionView.frame.height + 25, width: titleTextField.frame.size.width, height: titleTextField.frame.size.height)
    }

    DispatchQueue.main.async {
        self.mainScrollView.scrollRectToVisible(frame, animated: true)
    }
}
alexkaessner
  • 1,966
  • 1
  • 14
  • 39