0

I've spent most of the day on SO trying to figure this out, here's my problem:

I have a UIScrollView with a vertical stack view inside of it, and inside of the stack view I have several UIViews that contain different stuff. In the bottom view, I have a UITextView that I'd ideally like to move up whenever I start typing in it so I can actually see what I'm typing.

Implementing the solutions found here, here,here,here, and all the other similar prior questions on this topic works if I have a UITextField in the last view instead of a UITextView, but I really would like to have return key / multi-line functionality which seems to necessitate a UITextView.

Here's what I have in terms of code (per the several above links):

func registerForKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(_:)), name: .UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(_:)), name: .UIKeyboardWillHide, object: nil)
}

func keyboardWasShown(_ notification: NSNotification) {

    guard let info = notification.userInfo, let keyboardFrameValue = info[UIKeyboardFrameBeginUserInfoKey] as? NSValue else { return }

    let keyboardFrame = keyboardFrameValue.cgRectValue
    let keyboardSize = keyboardFrame.size

    let contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

}

func keyboardWillBeHidden(_ notification: NSNotification) {
    let contentInsets = UIEdgeInsets.zero
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

I've called registerForKeyboardNotifications() in viewDidLoad(), and this is working perfectly when I use a UITextField, but for whatever reason the functionality doesn't work with a UITextView. The closest SO question I could find to my issue is this one, but the question was never answered with a workable solution involving UITextView. I've seen several posts mention IQKeyboardManager, but I'd ideally like to fix this natively.

MachTurtle
  • 220
  • 3
  • 10

1 Answers1

0

I found a solution that combines contentInset and setContentOffset, but I'm sure it's not the most elegant one out there. However, if anyone else is having trouble getting a textView to move up with keyBoardWasShown, you can do the following:

Set up your viewController to notice when the keyboard shows up;

func registerForKeyboardNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(_:)), name: .UIKeyboardDidShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(_:)), name: .UIKeyboardWillHide, object: nil)
}

func keyboardWasShown(_ notification: NSNotification) {

    guard let info = notification.userInfo, let keyboardFrameValue = info[UIKeyboardFrameBeginUserInfoKey] as? NSValue else { return }

    let keyboardFrame = keyboardFrameValue.cgRectValue
    let keyboardSize = keyboardFrame.size

    let contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

}

func keyboardWillBeHidden(_ notification: NSNotification) {
    let contentInsets = UIEdgeInsets.zero
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets
}

Make sure to call registerForKeyboardNotifications() in viewDidLoad.

This is where it will vary depending on your particular setup. Since I had a view covering most of the screen real estate, I really only wanted my scrollView (which I made into an IBOutlet) to jump up enough to show part of my textView so that the user would know it was there and editable. This resulted in the following changes to the above portions of code dealing with the keyboard shown/hidden state;

func keyboardWasShown(_ notification: NSNotification) {

    guard let info = notification.userInfo, let keyboardFrameValue = info[UIKeyboardFrameBeginUserInfoKey] as? NSValue else { return }

    let keyboardFrame = keyboardFrameValue.cgRectValue
    let keyboardSize = keyboardFrame.size

    let contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height - 50.0, 0.0)
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    let bottom = keyboardSize.height - 60.0
    scrollView.setContentOffset(CGPoint(x: 0, y: bottom), animated: true)

}

func keyboardWillBeHidden(_ notification: NSNotification) {

    let contentInsets = UIEdgeInsets.zero
    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

}

The key item being the scrollView.setContentOffset part.

MachTurtle
  • 220
  • 3
  • 10