0

I am desperately trying to figure this out, I've spent all day on it with no luck. All I want to do is have a list of textfields that a user can click on and it will place the keyboard on the page so that A) the field is not blocked and (I have figured that part out) and B) the top of the view is not cut off when the keyboard pops up. This is what I have so far (https://i.stack.imgur.com/0qC0h.jpg), but you can clearly see the problem ~ that's the top of the view I cannot scroll up any farther. I've attempted to bury the whole thing in a scrollview and then change the contentsize of the scrollview but that has done nothing. Any help would be appreciated. Thank you. (I am trying to do this in swift 3).

class ViewController4: UIViewController,  UITextFieldDelegate {

    var dataState: Data?

    @IBOutlet weak var UserNameLabel: UILabel!

    @IBOutlet weak var TextField1Outlet: UITextField!


    @IBOutlet weak var TextField2Outlet: UITextField!

    @IBOutlet weak var TextField3Outlet: UITextField!


    @IBOutlet weak var TextField4Outlet: UITextField!


    @IBOutlet weak var TextField5Outlet: UITextField!

    @IBOutlet var ViewFrame: UIView!


    @IBOutlet weak var scrollView: UIScrollView!


    @IBAction func TextField1Action(_ sender: Any) {
    }

    @IBAction func TextField2Action(_ sender: Any) {
    }


    @IBAction func TextField3Action(_ sender: Any) {
    }


    @IBAction func TextField4Action(_ sender: Any) {
    }


    @IBAction func TextField5Action(_ sender: Any) {
    }


    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        UserNameLabel.text = dataState?.LoginName
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destinationViewController = segue.destination as? ViewController1 {
            destinationViewController.dataState = dataState
        }
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
        scrollView.delegate = self as? UIScrollViewDelegate

        TextField1Outlet.returnKeyType = UIReturnKeyType.done
        TextField1Outlet.delegate = self

        TextField2Outlet.returnKeyType = UIReturnKeyType.done
        TextField2Outlet.delegate = self

        TextField3Outlet.returnKeyType = UIReturnKeyType.done
        TextField3Outlet.delegate = self

        TextField4Outlet.returnKeyType = UIReturnKeyType.done
        TextField4Outlet.delegate = self

        TextField5Outlet.returnKeyType = UIReturnKeyType.done
        TextField5Outlet.delegate = self

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

    func keyboardWillShow(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
                let newHeight = self.view.frame.height + keyboardSize.height
                scrollView.contentSize = CGSize(width: self.view.frame.width, height: newHeight)

            }
        }
    }

    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
                scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height)
            }
        }
    }
}
Peter Weyand
  • 2,159
  • 9
  • 40
  • 72
  • Possible duplicate from here https://stackoverflow.com/questions/28813339/move-a-view-up-only-when-the-keyboard-covers-an-input-field If you're having issues getting this to work there is probably something off with your content size/constraint layout. I have working solution of this issue here with keyboard dismissal and scroll to the active textField. https://github.com/kingreza/UIScrollViewSample/tree/master – Reza Shirazian Jun 23 '17 at 22:36
  • Thanks Reza, those were the droids I was looking for. – Peter Weyand Jun 23 '17 at 22:49

2 Answers2

0

Use content insets instead of content size:

scrollView.contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: /* keyboard height */, right: 0.0)
Vasilii Muravev
  • 3,063
  • 17
  • 45
  • Ok, cool this is a 90% there solution. I used this tutorial snippet to get it to *almost* work: https://www.hackingwithswift.com/example-code/uikit/how-to-adjust-a-uiscrollview-to-fit-the-keyboard. The issue now is that when I close the window with `scrollView.contentInset = UIEdgeInsets.zero` I get extra space at the bottom. See here: http://imgur.com/a/GIHug. I thought the zero command should have completely eliminated the keyboard space, but apparently not. – Peter Weyand Jun 23 '17 at 22:34
  • @PeterWeyand Use `scrollView.contentOffset` to move textfields up and down, instead of changing view frame. – Vasilii Muravev Jun 24 '17 at 01:32
0

Backing up Vasilii Muravev answer you have one last mistake.

Step 1)

let insets = scrollView.contentInset
//Here you should save the PREVIOUS_BOTTOM
scrollView.contentInset = UIEdgeInsets(top: insets.top, left: insets.left, bottom: /* keyboard height */, right: insets.right)

Step 2)

let inset = scrollViewInset.contentInset
scrollView.contentInset = UIEdgeInsets(top: inset.top, left: inset.left, bottom: PREVIOUS_BOTTOM, right: inset.right)
facumenzella
  • 559
  • 3
  • 10