web-dev-qa-db-fra.com

Déplace le champ de texte lorsque le clavier semble rapide

J'utilise Swift pour programmer avec iOS et j'utilise ce code pour déplacer la UITextField, mais cela ne fonctionne pas. J'appelle la fonction keyboardWillShow correctement, mais le champ de texte ne bouge pas. J'utilise autolayout.

override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self);
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        //let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)

        var frame = self.ChatField.frame
        frame.Origin.y = frame.Origin.y - keyboardSize.height + 167
        self.chatField.frame = frame
        println("asdasd")
    }
}
180
Pedro Manfredi

Quelques améliorations doivent être apportées aux réponses existantes.

Tout d’abord, UIKeyboardWillChangeFrameNotification est probablement la meilleure notification car elle gère les modifications qui ne sont pas simplement affichées/masquées, mais qui sont dues aux modifications apportées au clavier (langue, utilisation de claviers tiers, etc.) et aux rotations (mais le commentaire ci-dessous indiquant également être pris en charge pour prendre en charge la connexion du clavier matériel).

Deuxièmement, les paramètres d'animation peuvent être extraits de la notification pour s'assurer que les animations sont bien ensemble.

Il existe probablement des options pour nettoyer ce code un peu plus, surtout si vous êtes à l'aise avec le déchirement forcé du code du dictionnaire.

Swift 3.x/4.x

class MyViewController: UIViewController {

// This constraint ties an element at zero points from the bottom layout guide
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?

override func viewDidLoad() {
    super.viewDidLoad()
    // Note that SO highlighting makes the new selector syntax (#selector()) look
    // like a comment but it isn't one
    NotificationCenter.default.addObserver(self,
        selector: #selector(self.keyboardNotification(notification:)),
        name: NSNotification.Name.UIKeyboardWillChangeFrame,
        object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame.Origin.y ?? 0
        let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
        if endFrameY >= UIScreen.main.bounds.size.height {
            self.keyboardHeightLayoutConstraint?.constant = 0.0
        } else {
            self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
        }
        UIView.animate(withDuration: duration,
                                   delay: TimeInterval(0),
                                   options: animationCurve,
                                   animations: { self.view.layoutIfNeeded() },
                                   completion: nil)
    }
}

(Edité pour tenir compte de l'animation hors-écran au clavier au lieu de la réduire, comme indiqué dans le commentaire génial de @ Gabox ci-dessous)

278
Joseph Lord

Si vous utilisez la disposition automatique, je suppose que vous avez défini le paramètre Bottom Space sur Superview contrainte. Si c'est le cas, vous devez simplement mettre à jour la valeur de la contrainte. Voici comment vous le faites avec un peu d'animation.

func keyboardWasShown(notification: NSNotification) {
    let info = notification.userInfo!
    let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()

    UIView.animateWithDuration(0.1, animations: { () -> Void in
        self.bottomConstraint.constant = keyboardFrame.size.height + 20
    })
}

Le 20 codé en dur est ajouté uniquement pour faire apparaître juste un peu le champ de texte au-dessus du clavier. Sinon, la marge supérieure du clavier et la marge inférieure du champ de texte se toucheraient.

Lorsque le clavier est désactivé, réinitialisez la valeur de la contrainte sur sa valeur d'origine.

120
Isuru

Une solution simple consiste à déplacer la vue vers le haut avec une constante de la hauteur du clavier.

override func viewDidLoad() {
   super.viewDidLoad()        
   NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
   NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}

func keyboardWillShow(sender: NSNotification) {
     self.view.frame.Origin.y = -150 // Move view 150 points upward 
}

func keyboardWillHide(sender: NSNotification) {
     self.view.frame.Origin.y = 0 // Move view to original position  
}

Swift 3

    NotificationCenter.default.addObserver(self, selector: #selector(RegisterViewController.keyboardWillShow(sender:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(RegisterViewController.keyboardWillHide(sender:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
88
Saqib Omer

J'aime le code propre à Swift. Voici donc le code le plus strict que je pourrais imaginer pour déplacer une vue de texte vers le haut/bas avec le clavier. Il travaille actuellement dans une application de production iOS8/9 Swift 2.

UPDATE (Mars 2016): Je viens de resserrer mon code précédent autant que possible. En outre, il existe un tas de réponses populaires ici qui codifient en dur la hauteur du clavier et les paramètres d'animation. Ce n'est pas nécessaire, pour ne pas mentionner que les nombres dans ces réponses ne correspondent pas toujours aux valeurs réelles que je vois sur mes 6s + iOS9 (hauteur du clavier de 226, durée de 0,25 et courbe d'animation de 7). Dans tous les cas, ce n'est presque pas du code supplémentaire pour obtenir ces valeurs directement du système. Voir ci-dessous.

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "animateWithKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
}

func animateWithKeyboard(notification: NSNotification) {

    // Based on both Apple's docs and personal experience, 
    // I assume userInfo and its documented keys are available.
    // If you'd like, you can remove the forced unwrapping and add your own default values.

    let userInfo = notification.userInfo!
    let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
    let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
    let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
    let moveUp = (notification.name == UIKeyboardWillShowNotification)

    // baseContraint is your Auto Layout constraint that pins the
    // text view to the bottom of the superview.

    baseConstraint.constant = moveUp ? -keyboardHeight : 0

    let options = UIViewAnimationOptions(rawValue: curve << 16)
    UIView.animateWithDuration(duration, delay: 0, options: options,
        animations: {
            self.view.layoutIfNeeded()
        },
        completion: nil
    )

}

REMARQUE: Ce code couvre la plupart des commentaires/cas généraux. Cependant, davantage de code peut être nécessaire pour gérer différentes orientations et/ou des claviers personnalisés Voici un article détaillé sur l'utilisation du clavier iOS. Si vous devez gérer tous les scénarios, cela peut aider.

20
scootermg

Edit: Je recommande une solution plus simple et plus propre. Il suffit de changer la classe de la contrainte d'espacement du bas en KeyboardLayoutConstraint . Il s'étendra automatiquement à la hauteur du clavier.


Ceci est une version améliorée de la réponse de @JosephLord. 

Comme testé sur iOS 8.3 iPad Simulator, Portrait. Xcode6.3 beta4, j'ai trouvé que sa réponse ne fonctionnait pas lorsque le clavier se cachait parce que UIKeyboardFrameEndUserInfoKey est "NSRect: {{0, 1024}, {768, 264}}";. La hauteur n'est jamais 0.

Cela revient à utiliser les traditionnels UIKeyboardWillShowNotification et UIKeyboardWillHideNotification pour mieux savoir quand le clavier se cache plutôt que de compter sur la hauteur de la dernière image. UIKeyboardWillShowNotification est également envoyé lorsque le cadre du clavier est modifié, de sorte qu'il devrait couvrir tous les cas d'utilisation.

    // You have to set this up in storyboard first!. 
    // It's a vertical spacing constraint between view and bottom of superview.
    @IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint! 

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillShowNotification, object: nil);
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillHideNotification, object: nil);
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    func keyboardNotification(notification: NSNotification) {

        let isShowing = notification.name == UIKeyboardWillShowNotification

        if let userInfo = notification.userInfo {
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
            let endFrameHeight = endFrame?.size.height ?? 0.0
            let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
            self.bottomSpacingConstraint?.constant = isShowing ? endFrameHeight : 0.0
            UIView.animateWithDuration(duration,
                delay: NSTimeInterval(0),
                options: animationCurve,
                animations: { self.view.layoutIfNeeded() },
                completion: nil)
        }
    }
14
Hlung

Ceci est une version améliorée de @JosephLord et de la réponse de @ Hlung. Il peut s’appliquer que vous ayez ou non une barre d’onglet. Et cela restaurerait parfaitement la vue déplacée par le clavier dans sa position initiale. 

// You have to set this up in storyboard first!. 
// It's a vertical spacing constraint between view and bottom of superview.
@IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint! 

override func viewDidLoad() {
        super.viewDidLoad()            

        //    Receive(Get) Notification
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillHideNotification, object: nil)


        self.originalConstraint = self.keyboardHeightLayoutConstraint?.constant //for original coordinate.
}

func keyboardNotification(notification: NSNotification) {
        let isShowing = notification.name == UIKeyboardWillShowNotification

        var tabbarHeight: CGFloat = 0
        if self.tabBarController? != nil {
            tabbarHeight = self.tabBarController!.tabBar.frame.height
        }
        if let userInfo = notification.userInfo {
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
            let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
            self.keyboardHeightLayoutConstraint?.constant = isShowing ? (endFrame!.size.height - tabbarHeight) : self.originalConstraint!
            UIView.animateWithDuration(duration,
                delay: NSTimeInterval(0),
                options: animationCurve,
                animations: { self.view.layoutIfNeeded() },
                completion: nil)
        }
}
7
Jeff Gu Kang

je travaille avec Swift 4 et je résous ce problème sans utiliser aucune contrainte supplémentaire du bas mon code est ici.il fonctionne vraiment sur mon cas

1) Ajouter Notification Observer dans le chargement 

override func viewDidLoad() {
        super.viewDidLoad()
        setupManager()
        // Do any additional setup after loading the view.
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }

2) Supprimer Notification Observer comme

deinit {
        NotificationCenter.default.removeObserver(self)
    }

3) Ajouter des méthodes d'affichage/masquage au clavier, telles que

 @objc func keyboardWillShow(notification: NSNotification) {
            if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
                UIView.animate(withDuration: 0.1, animations: { () -> Void in
                    self.view.frame.Origin.y -= keyboardSize.height
                    self.view.layoutIfNeeded()
                })
            }
        }

@objc func keyboardWillHide(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            UIView.animate(withDuration: 0.1, animations: { () -> Void in
                self.view.frame.Origin.y += keyboardSize.height
                self.view.layoutIfNeeded()
            })
        }
    }

4) Ajouter un délégué textfeild et ajouter des méthodes touchBegan .usefull pour masquer le clavier lorsque vous touchez en dehors de textfeild à l'écran

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true)

    }
7
pansora abhay

J'ai créé un protocole Swift 3 pour gérer l'apparence/disparition du clavier

import UIKit

protocol KeyboardHandler: class {

var bottomConstraint: NSLayoutConstraint! { get set }

    func keyboardWillShow(_ notification: Notification)
    func keyboardWillHide(_ notification: Notification)
    func startObservingKeyboardChanges()
    func stopObservingKeyboardChanges()
}


extension KeyboardHandler where Self: UIViewController {

    func startObservingKeyboardChanges() {

        // NotificationCenter observers
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        // Deal with rotations
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        // Deal with keyboard change (emoji, numerical, etc.)
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextInputCurrentInputModeDidChange, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillHide(notification)
        }
    }


    func keyboardWillShow(_ notification: Notification) {

      let verticalPadding: CGFloat = 20 // Padding between the bottom of the view and the top of the keyboard

      guard let value = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
      let keyboardHeight = value.cgRectValue.height

      // Here you could have more complex rules, like checking if the textField currently selected is actually covered by the keyboard, but that's out of this scope.
      self.bottomConstraint.constant = keyboardHeight + verticalPadding

      UIView.animate(withDuration: 0.1, animations: { () -> Void in
          self.view.layoutIfNeeded()
      })
  }


  func keyboardWillHide(_ notification: Notification) {
      self.bottomConstraint.constant = 0

      UIView.animate(withDuration: 0.1, animations: { () -> Void in
          self.view.layoutIfNeeded()
      })
  }


  func stopObservingKeyboardChanges() {
      NotificationCenter.default.removeObserver(self)
  }

}

Ensuite, pour l'implémenter dans un UIViewController, procédez comme suit:

  • laissez le viewController se conformer à ce protocole:

    class FormMailVC: UIViewControlle, KeyboardHandler {
    
  • commencer à observer les modifications du clavier dans viewWillAppear:

    // MARK: - View controller life cycle
    override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
      startObservingKeyboardChanges()
    }
    
  • arrêtez d'observer les modifications du clavier dans viewWillDisappear:

    override func viewWillDisappear(_ animated: Bool) {
      super.viewWillDisappear(animated)
      stopObservingKeyboardChanges()
    }
    
  • créez un IBOutlet pour la contrainte du bas à partir du storyboard:

    // NSLayoutConstraints
    @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
    

    (Je vous recommande d'intégrer l'ensemble de votre interface utilisateur dans un "contentView" et de lier à cette propriété la contrainte inférieure de cette contentView vers le guide de présentation inférieur)  Content view bottom constraint

  • change la priorité de contrainte de la contrainte top en 250 (faible)

 Content view top constraint

Cela permet de faire glisser toute la vue du contenu vers le haut lorsque le clavier apparaît .. La priorité doit être inférieure à toute autre priorité de contrainte dans les sous-vues, y compris les priorités de filtrage et de résistance du contenu.

  • Assurez-vous que votre autolayout a suffisamment de contraintes pour déterminer comment ContentView doit glisser vers le haut.

Vous devrez peut-être ajouter une contrainte "supérieur à égal" pour ceci:  "greater than equal" constraint

Et vous voilà!  Without keyboard

 With keyboard

6
Frédéric Adda

Cette simple UIViewController extension peut être utilisée

//MARK: - Observers
extension UIViewController {

    func addObserverForNotification(notificationName: String, actionBlock: (NSNotification) -> Void) {
        NSNotificationCenter.defaultCenter().addObserverForName(notificationName, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: actionBlock)
    }

    func removeObserver(observer: AnyObject, notificationName: String) {
        NSNotificationCenter.defaultCenter().removeObserver(observer, name: notificationName, object: nil)
    }
}

//MARK: - Keyboard observers
extension UIViewController {

    typealias KeyboardHeightClosure = (CGFloat) -> ()

    func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
        willHide willHideClosure: KeyboardHeightClosure?) {
            NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardWillChangeFrameNotification,
                object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: { [weak self](notification) in
                    if let userInfo = notification.userInfo,
                        let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue(),
                        let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
                        let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
                        let kFrame = self?.view.convertRect(frame, fromView: nil),
                        let kBounds = self?.view.bounds {

                            let animationType = UIViewAnimationOptions(rawValue: c)
                            let kHeight = kFrame.size.height
                            UIView.animateWithDuration(duration, delay: 0, options: animationType, animations: {
                                if CGRectIntersectsRect(kBounds, kFrame) { // keyboard will be shown
                                    willShowClosure?(kHeight)
                                } else { // keyboard will be hidden
                                    willHideClosure?(kHeight)
                                }
                                }, completion: nil)
                    } else {
                            print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
                    }
            })
    }

    func removeKeyboardObserver() {
        removeObserver(self, notificationName: UIKeyboardWillChangeFrameNotification)
    }
}

Exemple d'utilisation

override func viewWillDisappear(animated: Bool) {
        super.viewDidDisappear(animated)

        removeKeyboardObserver()
    }

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    addKeyboardChangeFrameObserver(willShow: { [weak self](height) in
        //Update constraints here
        self?.view.setNeedsUpdateConstraints()
        }, willHide: { [weak self](height) in
        //Reset constraints here
        self?.view.setNeedsUpdateConstraints()
    })
}

Solution Swift 4

//MARK: - Observers
extension UIViewController {

  func addObserverForNotification(_ notificationName: Notification.Name, actionBlock: @escaping (Notification) -> Void) {
    NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main, using: actionBlock)
  }

  func removeObserver(_ observer: AnyObject, notificationName: Notification.Name) {
    NotificationCenter.default.removeObserver(observer, name: notificationName, object: nil)
  }
}

//MARK: - Keyboard handling
extension UIViewController {

  typealias KeyboardHeightClosure = (CGFloat) -> ()

  func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
                                      willHide willHideClosure: KeyboardHeightClosure?) {
    NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame,
                                           object: nil, queue: OperationQueue.main, using: { [weak self](notification) in
                                            if let userInfo = notification.userInfo,
                                              let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
                                              let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
                                              let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
                                              let kFrame = self?.view.convert(frame, from: nil),
                                              let kBounds = self?.view.bounds {

                                              let animationType = UIViewAnimationOptions(rawValue: c)
                                              let kHeight = kFrame.size.height
                                              UIView.animate(withDuration: duration, delay: 0, options: animationType, animations: {
                                                if kBounds.intersects(kFrame) { // keyboard will be shown
                                                  willShowClosure?(kHeight)
                                                } else { // keyboard will be hidden
                                                  willHideClosure?(kHeight)
                                                }
                                              }, completion: nil)
                                            } else {
                                              print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
                                            }
    })
  }

  func removeKeyboardObserver() {
    removeObserver(self, notificationName: NSNotification.Name.UIKeyboardWillChangeFrame)
  }
}
5
ale_stro

Le moyen le plus simple qui ne nécessite aucun code:

  1. Téléchargez KeyboardLayoutConstraint.Swift et ajoutez (glissez/déposez) le fichier dans votre projet, si vous n'utilisez pas déjà le framework d'animation Spring.
  2. Dans votre storyboard, créez une contrainte inférieure pour l'objet/vue/champ de texte, sélectionnez la contrainte (double-cliquez dessus) et dans l'inspecteur d'identité, changez sa classe de NSLayoutConstraint à KeyboardLayoutConstraint.
  3. Terminé! 

L'objet se déplace automatiquement vers le haut avec le clavier, de manière synchronisée.

5
gammachill
struct MoveKeyboard {
    static let KEYBOARD_ANIMATION_DURATION : CGFloat = 0.3
    static let MINIMUM_SCROLL_FRACTION : CGFloat = 0.2;
    static let MAXIMUM_SCROLL_FRACTION : CGFloat = 0.8;
    static let PORTRAIT_KEYBOARD_HEIGHT : CGFloat = 216;
    static let LANDSCAPE_KEYBOARD_HEIGHT : CGFloat = 162;
}


  func textFieldDidBeginEditing(textField: UITextField) {
    let textFieldRect : CGRect = self.view.window!.convertRect(textField.bounds, fromView: textField)
    let viewRect : CGRect = self.view.window!.convertRect(self.view.bounds, fromView: self.view)

    let midline : CGFloat = textFieldRect.Origin.y + 0.5 * textFieldRect.size.height
    let numerator : CGFloat = midline - viewRect.Origin.y - MoveKeyboard.MINIMUM_SCROLL_FRACTION * viewRect.size.height
    let denominator : CGFloat = (MoveKeyboard.MAXIMUM_SCROLL_FRACTION - MoveKeyboard.MINIMUM_SCROLL_FRACTION) * viewRect.size.height
    var heightFraction : CGFloat = numerator / denominator

    if heightFraction < 0.0 {
        heightFraction = 0.0
    } else if heightFraction > 1.0 {
        heightFraction = 1.0
    }

    let orientation : UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown) {
        animateDistance = floor(MoveKeyboard.PORTRAIT_KEYBOARD_HEIGHT * heightFraction)
    } else {
        animateDistance = floor(MoveKeyboard.LANDSCAPE_KEYBOARD_HEIGHT * heightFraction)
    }

    var viewFrame : CGRect = self.view.frame
    viewFrame.Origin.y -= animateDistance

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))

    self.view.frame = viewFrame

    UIView.commitAnimations()
}


func textFieldDidEndEditing(textField: UITextField) {
    var viewFrame : CGRect = self.view.frame
    viewFrame.Origin.y += animateDistance

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)

    UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))

    self.view.frame = viewFrame

    UIView.commitAnimations()

}

Et enfin, puisque nous utilisons les méthodes des délégués

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

refactored from object-c http://www.cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html

4
Solomon Ayoola

Une autre solution qui ne dépend pas de l'autolayout, des contraintes ou des prises. Ce dont vous avez besoin est votre (vos) champ (s) dans une vue à défilement.

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "makeSpaceForKeyboard:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "makeSpaceForKeyboard:", name: UIKeyboardWillHideNotification, object: nil)
}

func makeSpaceForKeyboard(notification: NSNotification) {
    let info = notification.userInfo!
    let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
    let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double

    if notification.name == UIKeyboardWillShowNotification {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height - keyboardHeight
            self.view.frame = frame
        })
    } else {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height + keyboardHeight
            self.view.frame = frame
        })
    }

}
4
Simpa

Voici ma version pour une solution pour Swift 2.2: 

Commencez par vous inscrire au clavier pour afficher/masquer les notifications 

NSNotificationCenter.defaultCenter().addObserver(self,
                                                 selector: #selector(MessageThreadVC.keyboardWillShow(_:)),
                                                 name: UIKeyboardWillShowNotification,
                                                 object: nil)
NSNotificationCenter.defaultCenter().addObserver(self,
                                                 selector: #selector(MessageThreadVC.keyboardWillHide(_:)),
                                                 name: UIKeyboardWillHideNotification,
                                                 object: nil)

Ensuite, dans les méthodes correspondant à ces notifications, déplacez la vue principale vers le haut ou le bas

func keyboardWillShow(sender: NSNotification) {
if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
  self.view.frame.Origin.y = -keyboardSize.height
  }
}

func keyboardWillHide(sender: NSNotification) {
self.view.frame.Origin.y = 0
}

Le truc est dans la partie "keyboardWillShow" qui reçoit des appels à chaque fois que "QuickType Suggestion Bar" est développé ou réduit. Ensuite, nous définissons toujours la coordonnée y de la vue principale qui est égale à la valeur négative de la hauteur totale du clavier (avec ou sans la portion "Barre QuickType"). 

À la fin, n'oubliez pas d'éliminer les observateurs 

deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
4
Pavle Mijatovic

Voici une solution simple: le champ de texte est soumis à une contrainte qui le lie au guide de présentation inférieur. Il ajoute simplement la hauteur du clavier à la constante de la contrainte.

// This constraint ties the text field to the bottom layout guide
@IBOutlet var textFieldToBottomLayoutGuideConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name:UIKeyboardWillHideNotification, object: nil);
}

func keyboardWillShow(sender: NSNotification) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.textFieldToBottomLayoutGuideConstraint?.constant += keyboardSize.height
    }
}

func keyboardWillHide(sender: NSNotification) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.textFieldToBottomLayoutGuideConstraint?.constant -= keyboardSize.height
    }
}
3
echessa

Vous pouvez utiliser cette bibliothèque et une seule ligne de code dans appDidFinishedLaunching et vous avez terminé. 

func application(application: UIApplication,didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    IQKeyboardManager.sharedManager().enable = true
    return true
}

IQKeyboardManager - ajuste la vue à chaque apparition du clavierlink - https://github.com/hackiftekhar/IQKeyboardManager

3
Abdul Karim

Eh bien, je pense que je serais peut-être trop tard mais j'ai trouvé une autre version simple de la réponse de Saqib. J'utilise Autolayout avec des contraintes. J'ai une petite vue à l'intérieur d'une autre vue principale avec les champs nom d'utilisateur et mot de passe. Au lieu de changer la coordonnée y de la vue, j'enregistre la valeur de contrainte d'origine dans une variable et modifie la constante de la contrainte en une valeur, puis une fois que le clavier l'a annulée, je configure la contrainte en une contrainte d'origine. Cela évite ainsi le problème de la réponse de Saqib (la vue continue de monter et ne s’arrête pas). Ci-dessous mon code ... 

override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
    self.originalConstraint = self.centerYConstraint.constant
  }

  func keyboardWillShow(sender: NSNotification) {
    self.centerYConstraint.constant += 30
  }

  func keyboardWillHide(sender: NSNotification) {
    self.centerYConstraint.constant = self.originalConstraint
  }
3
Sashi

J'ai fait de la manière suivante:

Ceci est utile quand textfield superview est view

class AdminLoginViewController: UIViewController,
UITextFieldDelegate{

    @IBOutlet weak var txtUserName: UITextField!
    @IBOutlet weak var txtUserPassword: UITextField!
    @IBOutlet weak var btnAdminLogin: UIButton!

    private var activeField : UIView?

    var param:String!
    var adminUser : Admin? = nil
    var kbHeight: CGFloat!

    override func viewDidLoad()
    {
        self.addKeyBoardObserver()
        self.addGestureForHideKeyBoard()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func addGestureForHideKeyBoard()
    {
        let tapGesture = UITapGestureRecognizer(target: self, action: Selector("hideKeyboard"))
        tapGesture.cancelsTouchesInView = false
        view.addGestureRecognizer(tapGesture)
    }

    func hideKeyboard() {
        self.view.endEditing(true)
    }

    func addKeyBoardObserver(){

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "willChangeKeyboardFrame:",
name:UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "willChangeKeyboardFrame:",
name:UIKeyboardWillHideNotification, object: nil)
    }

    func removeObserver(){
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    //MARK:- textfiled Delegate

    func textFieldShouldBeginEditing(textField: UITextField) -> Bool
    {
         activeField = textField

        return true
    }
    func textFieldShouldEndEditing(textField: UITextField) -> Bool
    {
        if activeField == textField
        {
            activeField = nil
        }

        return true
    }

    func textFieldShouldReturn(textField: UITextField) -> Bool {

        if txtUserName == textField
        {
            txtUserPassword.becomeFirstResponder()
        }
        else if (textField == txtUserPassword)
        {
            self.btnAdminLoginAction(nil)
        }
        return true;
    }

    func willChangeKeyboardFrame(aNotification : NSNotification)
    {
       if self.activeField != nil && self.activeField!.isFirstResponder()
    {
        if let keyboardSize =  (aNotification.userInfo![UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
        {
            let dy = (self.activeField?.superview?.convertRect((self.activeField?.frame)!, toView: view).Origin.y)!

            let height = (self.view.frame.size.height - keyboardSize.size.height)

            if dy > height
            {
                var frame = self.view.frame

                frame.Origin.y = -((dy - height) + (self.activeField?.frame.size.height)! + 20)

                self.view.frame = frame
            }
        }
    }
    else
    {
        var frame = self.view.frame
        frame.Origin.y = 0
        self.view.frame = frame
    }
    } }
2
Krishna Gawade
 func registerForKeyboardNotifications()
    {
        //Keyboard
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWasShown), name: UIKeyboardDidShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillBeHidden), name: UIKeyboardDidHideNotification, object: nil)


    }
    func deregisterFromKeyboardNotifications(){

        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)

    }
    func keyboardWasShown(notification: NSNotification){

        let userInfo: NSDictionary = notification.userInfo!
        let keyboardInfoFrame = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue()

        let windowFrame:CGRect = (UIApplication.sharedApplication().keyWindow!.convertRect(self.view.frame, fromView:self.view))

        let keyboardFrame = CGRectIntersection(windowFrame, keyboardInfoFrame!)

        let coveredFrame = UIApplication.sharedApplication().keyWindow!.convertRect(keyboardFrame, toView:self.view)

        let contentInsets = UIEdgeInsetsMake(0, 0, (coveredFrame.size.height), 0.0)
        self.scrollViewInAddCase .contentInset = contentInsets;
        self.scrollViewInAddCase.scrollIndicatorInsets = contentInsets;
        self.scrollViewInAddCase.contentSize = CGSizeMake((self.scrollViewInAddCase.contentSize.width), (self.scrollViewInAddCase.contentSize.height))

    }
    /**
     this method will fire when keyboard was hidden

     - parameter notification: contains keyboard details
     */
    func keyboardWillBeHidden (notification: NSNotification) {

        self.scrollViewInAddCase.contentInset = UIEdgeInsetsZero
        self.scrollViewInAddCase.scrollIndicatorInsets = UIEdgeInsetsZero

    }
2
Kamalkumar.E

Réponse rapide 4.x, fusion des réponses de @Joseph Lord et de @Isuru. bottomConstraint représente la contrainte inférieure de la vue que vous souhaitez déplacer.

override func viewDidLoad() {
    // Call super
    super.viewDidLoad()

    // Subscribe to keyboard notifications
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(keyboardNotification(notification:)),
                                           name: UIResponder.keyboardWillChangeFrameNotification,
                                           object: nil)        
}


deinit {
    NotificationCenter.default.removeObserver(self)
}


@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        // Get keyboard frame
        let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

        // Set new bottom constraint constant
        let bottomConstraintConstant = keyboardFrame.Origin.y >= UIScreen.main.bounds.size.height ? 0.0 : keyboardFrame.size.height

        // Set animation properties
        let duration = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve = UIView.AnimationOptions(rawValue: animationCurveRaw)

        // Animate the view you care about
        UIView.animate(withDuration: duration, delay: 0, options: animationCurve, animations: {
            self.bottomConstraint.constant = bottomConstraintConstant
            self.view.layoutIfNeeded()
        }, completion: nil)
    }
}
1
Crashalot

Si vous êtes comme moi qui a essayé toutes les solutions ci-dessus et que votre problème n’est toujours pas résolu, j’ai une excellente solution pour vous qui fonctionne à merveille. Premièrement, je veux clarifier quelques points concernant certaines des solutions mentionnées ci-dessus.

  1. Dans mon cas, IQkeyboardmanager ne fonctionnait que si aucune mise en page automatique n'était appliquée aux éléments. S'il est appliqué, le gestionnaire IQkeyboard ne fonctionnera pas comme nous le pensons.
  2. Même chose avec le mouvement ascendant de self.view.
  3. j'ai écrit un en-tête Objective C avec un support Swift pour pousser UITexfield vers le haut lorsque l'utilisateur clique dessus, résolvant ainsi le problème du clavier couvrant le UITextfield: https://github.com/coolvasanth/smart_keyboard .
  4. Celui qui possède un niveau intermédiaire ou supérieur dans le développement d'applications iOS peut facilement comprendre le référentiel et le mettre en œuvre. Bonne chance
1
Vasanth

J'ai fait de la manière suivante: 

class SignInController: UIViewController , UITextFieldDelegate {

@IBOutlet weak var scrollView: UIScrollView!

// outlet declartion
@IBOutlet weak var signInTextView: UITextField!

var kbHeight: CGFloat!

/**
*
* @method viewDidLoad
*
*/

override func viewDidLoad() {
    super.viewDidLoad()

    self.signInTextView.delegate = self

}// end viewDidLoad

/**
*
* @method viewWillAppear
*
*/

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)

}// end viewWillAppear

/**
*
* @method viewDidAppear
*
*/

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)


}// end viewDidAppear

/**
*
* @method viewWillDisappear
*
*/
override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

/**
*
* @method textFieldShouldReturn
* retun the keyboard value
*
*/

// MARK -
func textFieldShouldReturn(textField: UITextField) -> Bool {
    signInTextView.resignFirstResponder()
    return true;

}// end textFieldShouldReturn

// MARK - keyboardWillShow
func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardSize =  (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            kbHeight = keyboardSize.height
            self.animateTextField(true)
        }
    }
}// end keyboardWillShow

// MARK - keyboardWillHide
func keyboardWillHide(notification: NSNotification) {
    self.animateTextField(false)
}// end keyboardWillHide

// MARK - animateTextField
func animateTextField(up: Bool) {
    var movement = (up ? -kbHeight : kbHeight)

    UIView.animateWithDuration(0.3, animations: {
        self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    })
}// end animateTextField

/**
*
* @method didReceiveMemoryWarning
*
*/

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.

}// end didReceiveMemoryWarning


}// end SignInController
1
Vinod Joshi

Si vous êtes comme moi, utilisez Autolayout et ne récupérez pas le clavier lorsque vous utilisez l'application sur un simulateur. C'est peut-être parce qu'Apple vous fait utiliser le clavier de votre ordinateur comme premier clavier.

Pour que le clavier de l'appareil apparaisse:

shift + cmd + K

Cela semble stupide mais j'aurais bien aimé trouver cette réponse il y a 3 heures :)

0
Cublax

Aucun d'entre eux n'a fonctionné et j'ai fini par utiliser des encarts de contenu pour déplacer ma vue vers le haut lorsque le clavier apparaît.

Note: J'utilisais une UITableView

Solution référencée @ keyboard-content-offset qui a été entièrement écrit en Objective C, la solution ci-dessous est propre à Swift.

Ajouter l'observateur de notification @ viewDidLoad ()

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourClass.keyboardWillBeShown), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourClass.keyboardWillBeHidden), name:UIKeyboardWillHideNotification, object: nil);

Pour obtenir la taille du clavier, nous obtenons d’abord le dictionnaire userInfo à partir de l’objet de notification, qui stocke tous les objets supplémentaires que notre récepteur pourrait utiliser. 

Ce dictionnaire permet d’obtenir l’objet CGRect décrivant le cadre du clavier en utilisant la clé UIKeyboardFrameBeginUserInfoKey.

Appliquez l'insert de contenu pour la méthode table view @ keyboardWillBeShown,

func keyboardWillBeShown(sender: NSNotification)
{        
    // Move the table view

    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
    {
        let contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);

        yourTableView.contentInset = contentInsets;

        yourTableView.scrollIndicatorInsets = contentInsets;
    }
}

Restaurez la méthode view @ keyboardWillBeHidden

func keyboardWillBeHidden(sender: NSNotification)
{
    // Moving back the table view back to the default position

    yourTableView.contentInset = UIEdgeInsetsZero;

    yourTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
}

Si vous souhaitez également tenir compte de l'orientation du périphérique, utilisez des instructions conditionnelles pour adapter le code à vos besoins.

// Portrait
UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);

// Landscape
UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.width), 0.0);
0
Vikram Ezhil

Il vous suffit de placer votre zone de texte dans une vue, puis de remplacer inputAccessoryView qui renvoie la vue. Important: votre vue doit être créée par programme. N'utilisez pas @IBOutlets.

 override var inputAccessoryView: UIView? {
    get {
        return newlyProgramaticallyCreatedView
    }}
0
Tenny Pinheiro
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

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

func keyboardWillShow(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
    }
}

func keyboardWillHide(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    }
}

enter image description here

0
Zany

Le meilleur moyen consiste à utiliser NotificationCenter pour intercepter les actions du clavier. Vous pouvez suivre les étapes décrites dans ce court article https://medium.com/@demirciy/keyboard-handling-deb1a96a8207

0
Yusuf Demirci

Swift 4.1,

Utilisez la classe TPKeyBoardAvoiding pour obtenir ceci . Cela fonctionne bien avec UIScrollView, UICollectionView, UITableView.

Attribuez simplement cette classe à votre scrollview, collectionview ou tableview dans le storyboard ou créez son objet par programmation . Tous les champs ou vues de texte à l'intérieur de TPKeyboardAvoiding scrollview s'ajustera automatiquement lorsque le clavier apparaîtra et disparaîtra.

Voici le lien pour TPKeyboardAvoiding

TPKeyboardAvoiding for Swift 4.1,

import Foundation
import UIKit

// MARK: - TableView
class TPKeyboardAvoidingTableView:UITableView,UITextFieldDelegate, UITextViewDelegate {

    override var frame:CGRect{
        willSet{
            super.frame = frame
        }

        didSet{
            if hasAutomaticKeyboardAvoidingBehaviour() {return}
            TPKeyboardAvoiding_updateContentInset()
        }
    }

    override var contentSize:CGSize{
        willSet(newValue){
            if hasAutomaticKeyboardAvoidingBehaviour() {
                super.contentSize = newValue
                return
            }

            if newValue.equalTo(self.contentSize)
            {
                return
            }

            super.contentSize = newValue
            self.TPKeyboardAvoiding_updateContentInset()
        }

        //        didSet{
        //            self.TPKeyboardAvoiding_updateContentInset()
        //        }
    }


    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame: frame, style: style)
        self.setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }

    override func awakeFromNib() {
        setup()
    }

    deinit{
        NotificationCenter.default.removeObserver(self)
    }

    func hasAutomaticKeyboardAvoidingBehaviour()->Bool
    {
        if #available(iOS 8.3, *) {
            if self.delegate is UITableViewController
            {
                return true
            }
        }

        return false
    }

    func focusNextTextField()->Bool
    {
        return self.TPKeyboardAvoiding_focusNextTextField()
    }

    @objc func scrollToActiveTextField()
    {
        return self.TPKeyboardAvoiding_scrollToActiveTextField()
    }

    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        if newSuperview != nil {
            NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.TPKeyboardAvoiding_findFirstResponderBeneathView(self)?.resignFirstResponder()
        super.touchesEnded(touches, with: event)
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)

        Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), userInfo: nil, repeats: false)
    }
}

private extension TPKeyboardAvoidingTableView
{
    func setup()
    {
        if self.hasAutomaticKeyboardAvoidingBehaviour() { return }

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(TPKeyboardAvoiding_keyboardWillShow(_:)),
                                               name: NSNotification.Name.UIKeyboardWillChangeFrame,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(TPKeyboardAvoiding_keyboardWillHide(_:)),
                                               name: NSNotification.Name.UIKeyboardWillHide,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(scrollToActiveTextField),
                                               name: NSNotification.Name.UITextViewTextDidBeginEditing,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(scrollToActiveTextField),
                                               name: NSNotification.Name.UITextFieldTextDidBeginEditing,
                                               object: nil)
    }
}

// MARK: - CollectionView
class TPKeyboardAvoidingCollectionView:UICollectionView,UITextViewDelegate {

    override var contentSize:CGSize{
        willSet(newValue){
            if newValue.equalTo(self.contentSize)
            {
                return
            }

            super.contentSize = newValue
            self.TPKeyboardAvoiding_updateContentInset()
        }

        //        didSet{
        //            self.TPKeyboardAvoiding_updateContentInset()
        //        }
    }


    override var frame:CGRect{
        willSet{
            super.frame = frame
        }

        didSet{
            self.TPKeyboardAvoiding_updateContentInset()
        }
    }

    //    override init(frame: CGRect) {
    //        super.init(frame: frame)
    //    }

    override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
        super.init(frame: frame, collectionViewLayout: layout)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        //        fatalError("init(coder:) has not been implemented")
        super.init(coder: aDecoder)
        self.setup()

    }

    override func awakeFromNib() {
        setup()
    }

    deinit{
        NotificationCenter.default.removeObserver(self)
    }

    func focusNextTextField()->Bool
    {
        return self.TPKeyboardAvoiding_focusNextTextField()
    }

    @objc func scrollToActiveTextField()
    {
        return self.TPKeyboardAvoiding_scrollToActiveTextField()
    }

    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        if newSuperview != nil {
            NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.TPKeyboardAvoiding_findFirstResponderBeneathView(self)?.resignFirstResponder()
        super.touchesEnded(touches, with: event)
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)

        Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), userInfo: nil, repeats: false)
    }
}

private extension TPKeyboardAvoidingCollectionView
{
    func setup()
    {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(TPKeyboardAvoiding_keyboardWillShow(_:)),
                                               name: NSNotification.Name.UIKeyboardWillChangeFrame,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(TPKeyboardAvoiding_keyboardWillHide(_:)),
                                               name: NSNotification.Name.UIKeyboardWillHide,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(scrollToActiveTextField),
                                               name: NSNotification.Name.UITextViewTextDidBeginEditing,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(scrollToActiveTextField),
                                               name: NSNotification.Name.UITextFieldTextDidBeginEditing,
                                               object: nil)
    }
}

// MARK: - ScrollView
class TPKeyboardAvoidingScrollView:UIScrollView,UITextFieldDelegate,UITextViewDelegate
{
    override var contentSize:CGSize{
        didSet{
            self.TPKeyboardAvoiding_updateFromContentSizeChange()
        }
    }


    override var frame:CGRect{
        didSet{
            self.TPKeyboardAvoiding_updateContentInset()
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setup()
    }

    override func awakeFromNib() {
        setup()
    }

    func contentSizeToFit()
    {
        self.contentSize = self.TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames()
    }

    func focusNextTextField() ->Bool
    {
        return self.TPKeyboardAvoiding_focusNextTextField()
    }

    @objc func scrollToActiveTextField()
    {
        return self.TPKeyboardAvoiding_scrollToActiveTextField()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }

    deinit{
        NotificationCenter.default.removeObserver(self)
    }

    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        if newSuperview != nil {
            NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.TPKeyboardAvoiding_findFirstResponderBeneathView(self)?.resignFirstResponder()
        super.touchesEnded(touches, with: event)
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), object: self)

        Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_:)), userInfo: nil, repeats: false)
    }
}

private extension TPKeyboardAvoidingScrollView
{
    func setup()
    {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(TPKeyboardAvoiding_keyboardWillShow(_:)),
                                               name: NSNotification.Name.UIKeyboardWillChangeFrame,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(TPKeyboardAvoiding_keyboardWillHide(_:)),
                                               name: NSNotification.Name.UIKeyboardWillHide,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(scrollToActiveTextField),
                                               name: NSNotification.Name.UITextViewTextDidBeginEditing,
                                               object: nil)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(scrollToActiveTextField),
                                               name: NSNotification.Name.UITextFieldTextDidBeginEditing,
                                               object: nil)
    }
}

// MARK: - Process Event
let kCalculatedContentPadding:CGFloat = 10;
let kMinimumScrollOffsetPadding:CGFloat = 20;

extension UIScrollView
{
    @objc func TPKeyboardAvoiding_keyboardWillShow(_ notification:Notification)
    {
        guard let userInfo = notification.userInfo else { return }
        guard let rectNotification = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else
        {
            return
        }

        let keyboardRect = self.convert(rectNotification.cgRectValue , from: nil)
        if keyboardRect.isEmpty
        {
            return
        }

        let state = self.keyboardAvoidingState()

        guard let firstResponder = self.TPKeyboardAvoiding_findFirstResponderBeneathView(self) else { return}
        state.keyboardRect = keyboardRect
        if !state.keyboardVisible
        {
            state.priorInset = self.contentInset
            state.priorScrollIndicatorInsets = self.scrollIndicatorInsets
            state.priorPagingEnabled = self.isPagingEnabled
        }

        state.keyboardVisible = true
        self.isPagingEnabled = false

        if self is TPKeyboardAvoidingScrollView
        {
            state.priorContentSize = self.contentSize
            if self.contentSize.equalTo(CGSize.zero)
            {
                self.contentSize = self.TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames()
            }
        }

        let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Float ?? 0.0
        let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int ?? 0
        let options = UIViewAnimationOptions(rawValue: UInt(curve))

        UIView.animate(withDuration: TimeInterval(duration),
                       delay: 0,
                       options: options,
                       animations: { [weak self]() -> Void in
                        if let actualSelf = self
                        {
                            actualSelf.contentInset = actualSelf.TPKeyboardAvoiding_contentInsetForKeyboard()
                            let viewableHeight = actualSelf.bounds.size.height - actualSelf.contentInset.top - actualSelf.contentInset.bottom
                            let point = CGPoint(x: actualSelf.contentOffset.x, y: actualSelf.TPKeyboardAvoiding_idealOffsetForView(firstResponder, viewAreaHeight: viewableHeight))
                            actualSelf.setContentOffset(point, animated: false)

                            actualSelf.scrollIndicatorInsets = actualSelf.contentInset
                            actualSelf.layoutIfNeeded()
                        }

        }) { (finished) -> Void in

        }
    }

    @objc func TPKeyboardAvoiding_keyboardWillHide(_ notification:Notification)
    {
        guard let userInfo = notification.userInfo else { return }

        guard let rectNotification = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue else
        {
            return
        }
        let keyboardRect = self.convert(rectNotification.cgRectValue , from: nil)
        if keyboardRect.isEmpty
        {
            return
        }
        let state = self.keyboardAvoidingState()

        if !state.keyboardVisible
        {
            return
        }
        state.keyboardRect = CGRect.zero
        state.keyboardVisible = false

        let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Float ?? 0.0
        let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int ?? 0
        let options = UIViewAnimationOptions(rawValue: UInt(curve))

        UIView.animate(withDuration: TimeInterval(duration),
                       delay: 0,
                       options: options,
                       animations: { [weak self]() -> Void in
                        if let actualSelf = self
                        {
                            if actualSelf is TPKeyboardAvoidingScrollView {
                                actualSelf.contentSize = state.priorContentSize
                                actualSelf.contentInset = state.priorInset
                                actualSelf.scrollIndicatorInsets = state.priorScrollIndicatorInsets
                                actualSelf.isPagingEnabled = state.priorPagingEnabled
                                actualSelf.layoutIfNeeded()
                            }
                        }

        }) { (finished) -> Void in

        }
    }

    func TPKeyboardAvoiding_updateFromContentSizeChange()
    {
        let state = self.keyboardAvoidingState()
        if state.keyboardVisible
        {
            state.priorContentSize = self.contentSize
        }
    }

    func TPKeyboardAvoiding_focusNextTextField() ->Bool
    {
        guard let firstResponder = self.TPKeyboardAvoiding_findFirstResponderBeneathView(self) else { return false}
        guard let view = self.TPKeyboardAvoiding_findNextInputViewAfterView(firstResponder, beneathView: self) else { return false}
        Timer.scheduledTimer(timeInterval: 0.1, target: view, selector: #selector(becomeFirstResponder), userInfo: nil, repeats: false)

        return true

    }

    func TPKeyboardAvoiding_scrollToActiveTextField()
    {
        let state = self.keyboardAvoidingState()

        if !state.keyboardVisible { return }

        let visibleSpace = self.bounds.size.height - self.contentInset.top - self.contentInset.bottom

        let idealOffset = CGPoint(x: 0,
                                  y: self.TPKeyboardAvoiding_idealOffsetForView(self.TPKeyboardAvoiding_findFirstResponderBeneathView(self),
                                                                                viewAreaHeight: visibleSpace))

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double((Int64)(0 * NSEC_PER_SEC)) / Double(NSEC_PER_SEC)) {[weak self] () -> Void in
            self?.setContentOffset(idealOffset, animated: true)
        }
    }

    //Helper
    func TPKeyboardAvoiding_findFirstResponderBeneathView(_ view:UIView) -> UIView?
    {
        for childView in view.subviews
        {
            if childView.responds(to: #selector(getter: isFirstResponder)) && childView.isFirstResponder
            {
                return childView
            }
            let result = TPKeyboardAvoiding_findFirstResponderBeneathView(childView)
            if result != nil
            {
                return result
            }
        }
        return nil
    }

    func TPKeyboardAvoiding_updateContentInset()
    {
        let state = self.keyboardAvoidingState()
        if state.keyboardVisible
        {
            self.contentInset = self.TPKeyboardAvoiding_contentInsetForKeyboard()
        }
    }

    func TPKeyboardAvoiding_calculatedContentSizeFromSubviewFrames() ->CGSize
    {
        let wasShowingVerticalScrollIndicator = self.showsVerticalScrollIndicator
        let wasShowingHorizontalScrollIndicator = self.showsHorizontalScrollIndicator

        self.showsVerticalScrollIndicator = false
        self.showsHorizontalScrollIndicator = false

        var rect = CGRect.zero

        for view in self.subviews
        {
            rect = rect.union(view.frame)
        }

        rect.size.height += kCalculatedContentPadding
        self.showsVerticalScrollIndicator = wasShowingVerticalScrollIndicator
        self.showsHorizontalScrollIndicator = wasShowingHorizontalScrollIndicator

        return rect.size
    }

    func TPKeyboardAvoiding_idealOffsetForView(_ view:UIView?,viewAreaHeight:CGFloat) -> CGFloat
    {
        let contentSize = self.contentSize

        var offset:CGFloat = 0.0
        let subviewRect =  view != nil ? view!.convert(view!.bounds, to: self) : CGRect.zero

        var padding = (viewAreaHeight - subviewRect.height)/2
        if padding < kMinimumScrollOffsetPadding
        {
            padding = kMinimumScrollOffsetPadding
        }

        offset = subviewRect.Origin.y - padding - self.contentInset.top

        if offset > (contentSize.height - viewAreaHeight)
        {
            offset = contentSize.height - viewAreaHeight
        }

        if offset < -self.contentInset.top
        {
            offset = -self.contentInset.top
        }

        return offset
    }

    func TPKeyboardAvoiding_contentInsetForKeyboard() -> UIEdgeInsets
    {
        let state = self.keyboardAvoidingState()
        var newInset = self.contentInset;

        let keyboardRect = state.keyboardRect
        newInset.bottom = keyboardRect.size.height - max(keyboardRect.maxY - self.bounds.maxY, 0)

        return newInset

    }

    func TPKeyboardAvoiding_viewIsValidKeyViewCandidate(_ view:UIView)->Bool
    {
        if view.isHidden || !view.isUserInteractionEnabled {return false}

        if view is UITextField
        {
            if (view as! UITextField).isEnabled {return true}
        }

        if view is UITextView
        {
            if (view as! UITextView).isEditable {return true}
        }

        return false
    }

    func TPKeyboardAvoiding_findNextInputViewAfterView(_ priorView:UIView,beneathView view:UIView, candidateView bestCandidate: inout UIView?)
    {
        let priorFrame = self.convert(priorView.frame, to: priorView.superview)
        let candidateFrame = bestCandidate == nil ? CGRect.zero : self.convert(bestCandidate!.frame, to: bestCandidate!.superview)

        var bestCandidateHeuristic = -sqrt(candidateFrame.Origin.x*candidateFrame.Origin.x + candidateFrame.Origin.y*candidateFrame.Origin.y) + ( Float(fabs(candidateFrame.minY - priorFrame.minY))<Float.ulpOfOne ? 1e6 : 0)

        for childView in view.subviews
        {
            if TPKeyboardAvoiding_viewIsValidKeyViewCandidate(childView)
            {
                let frame = self.convert(childView.frame, to: view)
                let heuristic = -sqrt(frame.Origin.x*frame.Origin.x + frame.Origin.y*frame.Origin.y)
                    + (Float(fabs(frame.minY - priorFrame.minY)) < Float.ulpOfOne ? 1e6 : 0)

                if childView != priorView && (Float(fabs(frame.minY - priorFrame.minY)) < Float.ulpOfOne
                    && frame.minX > priorFrame.minX
                    || frame.minY > priorFrame.minY)
                    && (bestCandidate == nil || heuristic > bestCandidateHeuristic)
                {
                    bestCandidate = childView
                    bestCandidateHeuristic = heuristic
                }
            }else
            {
                self.TPKeyboardAvoiding_findNextInputViewAfterView(priorView, beneathView: view, candidateView: &bestCandidate)
            }
        }
    }

    func TPKeyboardAvoiding_findNextInputViewAfterView(_ priorView:UIView,beneathView view:UIView) ->UIView?
    {
        var candidate:UIView?
        self.TPKeyboardAvoiding_findNextInputViewAfterView(priorView, beneathView: view, candidateView: &candidate)
        return candidate
    }


    @objc func TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(_ obj: AnyObject)
    {
        func processWithView(_ view: UIView) {
            for childView in view.subviews
            {
                if childView is UITextField || childView is UITextView
                {
                    self.TPKeyboardAvoiding_initializeView(childView)
                }else
                {
                    self.TPKeyboardAvoiding_assignTextDelegateForViewsBeneathView(childView)
                }
            }
        }

        if let timer = obj as? Timer, let view = timer.userInfo as? UIView {
            processWithView(view)
        }
        else if let view = obj as? UIView {
            processWithView(view)
        }
    }

    func TPKeyboardAvoiding_initializeView(_ view:UIView)
    {
        if let textField = view as? UITextField,
            let delegate = self as? UITextFieldDelegate, textField.returnKeyType == UIReturnKeyType.default &&
            textField.delegate !== delegate
        {
            textField.delegate = delegate
            let otherView = self.TPKeyboardAvoiding_findNextInputViewAfterView(view, beneathView: self)
            textField.returnKeyType = otherView != nil ? .next : .done

        }
    }

    func keyboardAvoidingState()->TPKeyboardAvoidingState
    {
        var state = objc_getAssociatedObject(self, &AssociatedKeysKeyboard.DescriptiveName) as? TPKeyboardAvoidingState
        if state == nil
        {
            state = TPKeyboardAvoidingState()
            self.state = state
        }

        return self.state!
    }

}

// MARK: - Internal object observer
internal class TPKeyboardAvoidingState:NSObject
{
    var priorInset = UIEdgeInsets.zero
    var priorScrollIndicatorInsets = UIEdgeInsets.zero

    var keyboardVisible = false
    var keyboardRect = CGRect.zero
    var priorContentSize = CGSize.zero

    var priorPagingEnabled = false
}

internal extension UIScrollView
{
    fileprivate struct AssociatedKeysKeyboard {
        static var DescriptiveName = "KeyBoard_DescriptiveName"
    }

    var state:TPKeyboardAvoidingState?{
        get{
            let optionalObject:AnyObject? = objc_getAssociatedObject(self, &AssociatedKeysKeyboard.DescriptiveName) as AnyObject?
            if let object:AnyObject = optionalObject {
                return object as? TPKeyboardAvoidingState
            } else {
                return nil
            }
        }
        set{
            objc_setAssociatedObject(self, &AssociatedKeysKeyboard.DescriptiveName, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}
0
Pramod More

J'ai modifié la solution @Simpa un peu .........

override func viewDidLoad() 
{

    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("makeSpaceForKeyboard:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("makeSpaceForKeyboard:"), name:UIKeyboardWillHideNotification, object: nil);
}

deinit{
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

var keyboardIsVisible = false
override func makeSpaceForKeyboard(notification: NSNotification) {

    let info = notification.userInfo!
    let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
    let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double

    if notification.name == UIKeyboardWillShowNotification && keyboardIsVisible == false{

        keyboardIsVisible = true

        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height - keyboardHeight
            self.view.frame = frame
        })

    } else if keyboardIsVisible == true && notification.name == UIKeyboardWillShowNotification{

    }else {
        keyboardIsVisible = false

        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height + keyboardHeight
            self.view.frame = frame
        })
    }
}
0
Cloy

La solution Swift 4 que j'utilise prend la taille du clavier. Remplacez serverStatusStackView par la vue qui vous intéresse, par exemple: self.view:

deinit {
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        serverStatusStackView.frame.Origin.y = keyboardSize.height * 2 - serverStatusStackView.frame.height
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        serverStatusStackView.frame.Origin.y += keyboardSize.height
    }
}

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

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
0
A T

Voici une solution générique pour toutes les étapes TextField -

1) Créer un ViewController commun étendu par d’autres ViewControllers

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

}
 @objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.Origin.y == 0 {
            self.view.frame.Origin.y -= getMoveableDistance(keyboarHeight: keyboardSize.height)
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.Origin.y != 0 {
        self.view.frame.Origin.y = 0
    }
}
deinit {
    NotificationCenter.default.removeObserver(self)
}

//get the distance to move up the main view for the focus textfiled
func getMoveableDistance(keyboarHeight : CGFloat) ->  CGFloat{
    var y:CGFloat = 0.0
    if let activeTF = getSelectedTextField(){
        var tfMaxY = activeTF.frame.maxY
        var containerView = activeTF.superview!
        while containerView.frame.maxY != self.view.frame.maxY{
            let contViewFrm = containerView.convert(activeTF.frame, to: containerView.superview)
            tfMaxY = tfMaxY + contViewFrm.minY
            containerView = containerView.superview!
        }
        let keyboardMinY = self.view.frame.height - keyboarHeight
        if tfMaxY > keyboardMinY{
            y = (tfMaxY - keyboardMinY) + 10.0
        }
    }

    return y
}

2) Créer une extension de UIViewController et du TextField actuellement actif

//get active text field

extension UIViewController {func getSelectedTextField () -> UITextField? {

    let totalTextFields = getTextFieldsInView(view: self.view)

    for textField in totalTextFields{
        if textField.isFirstResponder{
            return textField
        }
    }

    return nil

}

func getTextFieldsInView(view: UIView) -> [UITextField] {

    var totalTextFields = [UITextField]()

    for subview in view.subviews as [UIView] {
        if let textField = subview as? UITextField {
            totalTextFields += [textField]
        } else {
            totalTextFields += getTextFieldsInView(view: subview)
        }
    }

    return totalTextFields
}

}

0
Mintu Borah