简体   繁体   中英

Moving UIView up only when the keyboard blocks the UITextField / UITextView

This has been asked a few times before: 1 2 3 4

These threads did not provide the solution I was looking for, and are getting a bit outdated with the release of Swift 5, so I've posted my solution below.

This is my current solution:

import UIKit

// For UITextViews, exact same code, but using UITextViewDelegate
class viewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var textField: UITextField!
    
    // Keeps track of our editing frame
    // Kept it as a CGRect so that it can work with both UITextFields and UITextViews
    var editingFrame: CGRect?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Set the delegate for the textField(s)
        textField.delegate = self
        
        // Add notification observers for keyboard
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChangeFrame(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }
    
    func textFieldDidBeginEditing(_ textField: UITextField) {
        editingFrame = textField.frame
        
        // This is the bit that is important, especially if you have
        // your textfield inside another view (UIStackViews for example)
        // The loop essentially goes through each successive superview the textfield has
        // and redefines the centre in that superview's frame of reference
        var currentView: UIView? = textField.superview
        while currentView != nil {
            editingFrame?.origin.x += currentView?.frame.origin.x ?? CGFloat(0.0)
            editingFrame?.origin.y += currentView?.frame.origin.y ?? CGFloat(0.0)
            currentView = currentView?.superview
        }
    }
    
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        editingFrame = nil
        return true
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        view.endEditing(true)
        return true
    }
    
    @objc func keyboardWillChangeFrame(notification: Notification) {
        if let editingFrame = editingFrame {
            if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect) {
                let offset = editingFrame.maxY - keyboardSize.minY
                if offset > self.view.frame.origin.y {
                    self.view.frame.origin.y -= offset
                } else {
                    if self.view.frame.origin.y != 0 {
                        self.view.frame.origin.y = 0
                    }
                }
            }
        } else {
            if self.view.frame.origin.y != 0 {
                self.view.frame.origin.y = 0
            }
        }
    }
    
    @objc func endEditingTextFields() {
        view.endEditing(true)
    }
}

I recommend using IQKeyboardManagerSwift (or IQKeyboardManager written in ObjC) library that you can install with cocoapods, all tutorials included in link. For me it works better that custom solutions. Here are 2 versions of the library, ObjC and Swift :

Swift verion: https://cocoapods.org/pods/IQKeyboardManagerSwift

ObjC version: https://cocoapods.org/pods/IQKeyboardManager

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM