Déplacer le champ de texte lorsque le clavier apparaît rapidement


217

J'utilise Swift pour programmer avec iOS et j'utilise ce code pour déplacer le UITextField, mais cela ne fonctionne pas. J'appelle la fonction keyboardWillShowcorrectement, mais le champ de texte ne bouge pas. J'utilise la mise en page automatique.

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")
    }
}

2
Guide pas à pas avec les fichiers du projet: codebeaulieu.com/43/…
Dan Beaulieu

Peut-être que deinit et viewDidLoad ne sont pas équilibrés.
Ricardo

Basé sur les documents et l'expérience personnelle d'Apple. Voici mon dépôt git en utilisant UIScrollView pour déplacer TF: github.com/29satnam/MoveTextFieldWhenKeyboardAppearsSwift
Codetard

Réponses:


315

Il y a quelques améliorations à apporter aux réponses existantes.

Premièrement, l' UIKeyboardWillChangeFrameNotification est probablement la meilleure notification car elle gère les modifications qui ne sont pas seulement affichées / masquées mais les modifications dues aux changements de clavier (langue, utilisation de claviers tiers, etc.) et les rotations aussi (mais notez le commentaire ci-dessous indiquant que le clavier se cachera devrait également pris en charge pour prendre en charge la connexion matérielle du clavier).

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

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

Swift 3

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)
    }
}

(Modifié pour tenir compte de l'animation du clavier hors écran au lieu de rétrécir, selon le commentaire impressionnant de @ Gabox ci-dessous)

Swift 5

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: UIResponder.keyboardWillChangeFrameNotification,
        object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame?.origin.y ?? 0
        let duration:TimeInterval = (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 = UIView.AnimationOptions(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)
    }
}

1
@JosephLord nice. mais j'ai trouvé que cela ne fonctionne pas lorsque le clavier se cache car il endFrame?.size.heightn'est pas nul. J'ai le cadre de fin comme UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 1024}, {768, 264}}";. Exécuté sur iOS 8.3 iPad Simulator, Portrait. Xcode6.3 beta4.
Hlung

8
si le clavier ne se cache pas, essayez d'utiliser ce code si endFrame? .origin.y> = UIScreen.mainScreen (). bounds.size.height {self.keyboardHeightLayoutConstraint? .constant = 0.0} else {self.keyboardHeightLayoutConstraint? .constant = endFrame.size.height}
Gabriel Goncalves

3
keyBoardHeightLayoutConstraint est une contrainte définie dans InterfaceBuilder contraignant le bas de la vue que vous souhaitez déplacer / réduire vers le guide de disposition inférieur ou le bas de la vue principale pour le contrôleur de vue. La constante est initialement définie sur zéro et sera ajustée pour faire de la place au clavier lorsque le clavier apparaît ou change de taille.
Joseph Lord

2
Notez que .UIKeyboardWillChangeFramecela ne se déclenche pas lorsqu'un clavier matériel est connecté, même si le clavier iOS disparaît. Vous devez également observer .UIKeyboardWillHidepour attraper ce cas de bord.
jamesk

1
@Sulthan fonctionne bien .. Mon problème est que cela devient un peu plus élevé que le clavier. existe-t-il un moyen de résoudre ce problème?
Pavlos

128

Si vous utilisez la mise en page automatique, je suppose que vous avez défini la contrainte Espace inférieur sur Superview . Si c'est le cas, il vous suffit de 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 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 fermé, réinitialisez la valeur de la contrainte à sa valeur d'origine.


1
Pouvez-vous m'expliquer comment je le définis? Merci! je contrôle toujours tout sur le storyboard
Pedro Manfredi

4
bottomConstraint est le nom que j'ai donné à la contrainte. J'ai sélectionné le constrant, j'ai fait glisser et créé un IBOutlet et j'ai donné ce nom. Vous pouvez créer des IBOutlets aux contraintes comme vous pouvez le faire avec d'autres éléments d'interface utilisateur comme les boutons et les champs de texte.
Isuru

2
Cette réponse a très bien fonctionné, sauf que l'animation s'est produite immédiatement pour moi. Cochez Comment animer les changements de contrainte? pour savoir comment animer correctement.
Adam Johns

2
@ vinbhai4u Vous devez vous inscrire pour recevoir une UIKeyboardWillShowNotificationnotification. Regardez le code dans la question du PO.
Isuru

8
@AdamJohns Pour animer le changement de contrainte, mettez à jour la constante à l'extérieur de animateWithDurationet appelez self.view.layoutIfNeeded()à l'intérieur du bloc d'animation.
Max

110

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

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);
}

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

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

Swift 5:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(sender:)), name: UIResponder.keyboardWillShowNotification, object: nil);

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(sender:)), name: UIResponder.keyboardWillHideNotification, object: nil);

4
J'aime cette solution simple. Mais j'ai ajouté un booléen keyboardShowing puisque j'ai déplacer plus d'un champ de texte. Je ne déplace le clavier qu'une seule fois pendant qu'il s'affiche. Merci.
Ken

2
au lieu de déplacer la vue, déplacez le texteView
ericgu

1
Cela conservera moins la valeur y de la vue si l'utilisateur change de langue d'entrée.
Jeffrey Neo

au lieu de changer la valeur self.view que j'ai fait self.myConstraint, cela fonctionne mais le fait est que la vue (à laquelle la contrainte est appliquée) continue de monter. Quelqu'un at-il été confronté à ce problème?
Sashi

5
Au lieu d'utiliser l' self.view.frame.origin.y -= 150utilisation self.view.frame.origin.y = -150et au lieu de l' self.view.frame.origin.y += 150utilisation self.view.frame.origin.y = 0. Cela empêche la vue de bouger de 150 chaque fois qu'un nouveau champ est touché.
gunwin

43

Pour déplacer votre vue lors de la modification du champ de texte, essayez ceci, je l'ai appliqué,

Option 1: - ** ** Mise à jour dans Swift 5.0 et iPhone X, XR, XS et XS Max Move à l'aide de NotificationCenter

  • Enregistrez cette notification dans func viewWillAppear(_ animated: Bool)

  • Désenregistrer cette notification dans func viewWillDisappear(_ animated: Bool)

Remarque: - Si vous ne vous désenregistrez pas, il appellera de la classe enfant et provoquera un plantage ou autre.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillShow(notification:)), name:  UIResponder.keyboardWillShowNotification, object: nil )
}
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}

@objc func keyboardWillShow( notification: Notification) {
    if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
        var newHeight: CGFloat
        let duration:TimeInterval = (notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
        if #available(iOS 11.0, *) {
            newHeight = keyboardFrame.cgRectValue.height - self.view.safeAreaInsets.bottom
        } else {
            newHeight = keyboardFrame.cgRectValue.height
        }
        let keyboardHeight = newHeight  + 10 // **10 is bottom margin of View**  and **this newHeight will be keyboard height**
        UIView.animate(withDuration: duration,
                       delay: TimeInterval(0),
                       options: animationCurve,
                       animations: {
                        self.view.textViewBottomConstraint.constant = keyboardHeight **//Here you can manage your view constraints for animated show**
                        self.view.layoutIfNeeded() },
                       completion: nil)
    }
}

Option 2: - Son travail fonctionne bien

func textFieldDidBeginEditing(textField: UITextField) {
        self.animateViewMoving(up: true, moveValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
        self.animateViewMoving(up: false, moveValue: 100)
}

func animateViewMoving (up:Bool, moveValue :CGFloat){
    var movementDuration:NSTimeInterval = 0.3
    var movement:CGFloat = ( up ? -moveValue : moveValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration )
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}

J'ai obtenu cette réponse de cette source UITextField remonter lorsque le clavier apparaît dans Swift

DANS LE SWIFT 4 ---

func textFieldDidBeginEditing(_ textField: UITextField) {
        animateViewMoving(up: true, moveValue: 100)
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        animateViewMoving(up: false, moveValue: 100)
    }
    func animateViewMoving (up:Bool, moveValue :CGFloat){
        let movementDuration:TimeInterval = 0.3
        let movement:CGFloat = ( up ? -moveValue : moveValue)
        UIView.beginAnimations( "animateView", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(movementDuration ) 
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }

1
@ Jogendra.Com, Merci pour votre work.But dur, il fonctionne mieux sur iPhone 5,4s et 6.But, comment puis - je désactiver sur iPhone et iPad 6plus (Ones plus)
Thiha Aung

Si vous utilisez l'option 1, assurez-vous d'ajouter une contrainte IBOutlet. Vous allez créer une contrainte que vous souhaitez redimensionner à l'aide de la mise en page automatique, puis la faire glisser vers le viewcontroller pour créer un IBOutlet que je référence en tant que self.iboutletConstraint.constant dans la fonction d'animation. De plus, cela ne réajuste pas la prise en cachant le clavier, j'ai géré cela en réinitialisant la contrainte à sa valeur d'origine.
Hammad Tariq

21

J'adore le code Swift propre. Voici donc le code le plus serré que j'ai pu trouver pour déplacer une vue texte vers le haut / bas avec le clavier. Il fonctionne actuellement dans une application de production iOS8 / 9 Swift 2.

MISE À JOUR (mars 2016): Je viens de resserrer mon code précédent autant que possible. En outre, il existe ici un tas de réponses populaires qui codent en dur la hauteur du clavier et les paramètres d'animation. Ce n'est pas nécessaire, sans mentionner que les chiffres dans ces réponses ne correspondent pas toujours aux valeurs réelles que je vois sur mon 6s + iOS9 (hauteur de clavier de 226, durée de 0,25 et courbe d'animation de 7). Dans tous les cas, ce n'est presque pas de 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 le cas le plus général / commentaire. Cependant, plus de code peut être nécessaire pour gérer différentes orientations et / ou 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 vous aider.


Semble être Swift 1.1 et je pense que ne compilera pas dans Swift 1.2 car il utilise aspour les lancements de force. as!peut fonctionner mais comme vous pouvez le voir ailleurs sur cette page, j'évite les lancers de force et le déballage de force moi-même.
Joseph Lord

Compile maintenant dans Swift 1.2. Et j'ai ajouté un commentaire au code re: le déballage forcé. À votre santé.
scootermg

Oups. Je voulais dire Swift 2.
scootermg

Selon la façon dont vous avez lié votre , baseConstraintil pourrait être au baseConstraint.constant = moveUp ? keyboardHeight : 0lieu de baseConstraint.constant = moveUp ? -keyboardHeight : 0.
limfinity

15

Edit : je recommande une solution plus simple et plus propre. Modifiez simplement la classe de contrainte d'espacement inférieur en KeyboardLayoutConstraint . Il s'étendra automatiquement à la hauteur du clavier.


Il s'agit d'une version améliorée de la réponse de @JosephLord.

Testé sur iOS 8.3 iPad Simulator, Portrait. Xcode6.3 beta4, j'ai trouvé que sa réponse ne fonctionne pas lorsque le clavier se cache parce qu'il l' UIKeyboardFrameEndUserInfoKeyest "NSRect: {{0, 1024}, {768, 264}}";. La hauteur n'est jamais0 .

Cela revient à utiliser le traditionnel UIKeyboardWillShowNotificationet UIKeyboardWillHideNotificationà mieux savoir quand le clavier se cache plutôt que de se fier à la hauteur du cadre final. UIKeyboardWillShowNotificationest également envoyé lorsque le cadre du clavier est modifié, il doit donc 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)
        }
    }

Pourriez-vous expliquer votre modification? Je ne pouvais pas le faire fonctionner. J'ai un UIScrollView avec un bouton en bas. J'ai réglé la classe à la contrainte de marge inférieure sur le fond.
schw4ndi

@ schw4ndi à quelles vues vos contraintes de fond sont-elles liées? il doit connecter le bas de scrollview au bas de la vue d'ensemble de ce scrollview.
Hlung

Oh merci, j'ai eu la contrainte entre le bouton et le scrollView
schw4ndi

9

je travaille avec swift 4 et je suis résolu ce problème sans utiliser de contrainte de fond supplémentaire regardez mon code est ici.il fonctionne vraiment sur mon cas

1) Ajouter un observateur de notification 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) Ajoutez des méthodes d'affichage / masquage du clavier comme

 @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 touchesBegan. Utiles pour masquer le clavier lorsque vous touchez en dehors du textfeild à l'écran

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

    }

doit êtreUIKeyboardFrameEndUserInfoKey
Micro

1
NSNotification.Name.UIKeyboardWillShow est renommé UIResponder.keyboardWillShowNotificationaussi UIKeyboardFrameBeginUserInfoKey enUIResponder.keyboardFrameBeginUserInfoKey
smj

7

Il s'agit d'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 de tabulations. Et cela rétablirait parfaitement la vue déplacée par le clavier à sa position d'origine.

// 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)
        }
}

6

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

  1. Télécharger KeyboardLayoutConstraint.swift et ajoutez (faites glisser et 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 en KeyboardLayoutConstraint.
  3. Terminé!

L'objet se déplace automatiquement vers le haut avec le clavier, en synchronisation.


2
Excellente solution! Mais vous avez besoin du Safe Area.Bottom comme premier élément de la contrainte (ne fonctionnait pas pour moi quand c'était le deuxième élément). Et cela fonctionnait mieux avec la constante définie sur 0 car elle préserve la constante et l'ajuste, plutôt que de la déplacer suffisamment loin pour afficher le champ et le clavier.
Mythlandia

Avez-vous la version KeyboardLayoutConstraint swift4?
jeet.chanchawat

6

J'ai créé un protocole Swift 3 pour gérer l'apparence / la 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êter d'observer les changements de clavier dans viewWillDisappear:

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

    // NSLayoutConstraints
    @IBOutlet weak var bottomConstraint: NSLayoutConstraint!

    (Je recommande d'avoir toute votre interface utilisateur intégrée dans une "contentView" et de lier à cette propriété la contrainte inférieure de cette contentView au guide de mise en page inférieur) Contrainte inférieure de l'affichage du contenu

  • changer la priorité de contrainte de la contrainte supérieure à 250 (faible)

Contrainte supérieure de la vue de contenu

Il s'agit de laisser la vue du contenu entier glisser 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 d'ajustement de contenu / les priorités de résistance à la compression de contenu.

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

Vous devrez peut-être ajouter une contrainte «supérieure à égale» pour cela: contrainte "supérieure à égale"

Et c'est parti! Sans clavier

Avec clavier


Cela fonctionne si vous mettez également "Relation = Equal", sans avertissements.
Valtoni Boaventura

Si vous mettez une relation égale, cela peut ne fonctionner que dans des situations spécifiques. Dans d'autres, vous pouvez avoir un avertissement d'incohérence de mise en page automatique. Cela dépend de votre propre mise en page. C'est pourquoi j'ai dit "vous devrez peut-être".
Frédéric Adda

Ok Frédéric, d'accord. C'était une bonne solution!
Valtoni Boaventura

manquantimport UIKit
Mirko

6

Une telle UIViewController extension simple 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.viewWillDisappear(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)
  }
}

Swift 4.2

//MARK: - Keyboard handling
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)
    }

    typealias KeyboardHeightClosure = (CGFloat) -> ()

    func removeKeyboardObserver() {
        removeObserver(self, notificationName: UIResponder.keyboardWillChangeFrameNotification)
    }

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

                                                    let animationType = UIView.AnimationOptions(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")
                                                }
        })
    }
}

2
beaucoup plus "Swift" que les autres solutions / fonctionne très bien / réutilisable dans chaque contrôleur sans tout réécrire -> certainement le meilleur ici :)
Tib

J'ai essayé mais aucune chance, UIScrollView est-il nécessaire ou quoi?
erdemgc

@erdemgc avez-vous vu un exemple d'utilisation? Tout ce dont vous avez besoin est simplement UIViewControlller + addKeyboardChangeFrameObserver et n'oubliez pas de le supprimer
ale_stro

La removeKeyboardObserver()méthode ici ne supprime pas réellement l'observateur. Si vous n'appelez pas cela, vous verrez un Invalid conditions for UIKeyboardWillChangeFrameNotificationdans la console à partir de la méthode add. Si vous appelez cela, vous verrez la même erreur, ce qui signifie que l'observateur n'est pas supprimé. La documentation indique «Pour annuler l'enregistrement des observations, vous passez l'objet renvoyé par cette méthode à removeObserver(_:)». Donc, ce que vous faites à la place est d'enregistrer l'objet retourné par cette méthode, puis de le passer lorsque vous souhaitez supprimer l'observateur.
Huy-Anh Hoang

En fait, une fois que scrollview est chargé, une valeur est attribuée à bound et vous ne pouvez pas détecter si un clavier sera masqué si le cadre du clavier intersecte avec bound.
James Kim

5

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 - ajustez la vue chaque fois que le clavier apparaît lien - https://github.com/hackiftekhar/IQKeyboardManager


4
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 des méthodes de délégués

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

refactorisé d'utiliser objective-c http://www.cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html


Cette solution a fonctionné pour moi, même si je devais faire un travail supplémentaire: déclarer un var animateDistance: CGFloat!plus, je devais gérer la UIKeyboardWillHideNotification lorsque l'utilisateur appuie sur le bouton Masquer le clavier.
Rhuantavan

4

Une autre solution qui ne dépend pas de la mise en page automatique, des contraintes ou des sorties. Ce dont vous avez besoin, c'est de vos champs dans une vue déroulante.

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
        })
    }

}

1
Il montre un écran noir après avoir UIKeyboardWillShowNotificationappelé.
Sachin Kumaram

4

Voici ma version pour une solution pour Swift 2.2:

Inscrivez-vous d'abord aux notifications Afficher / Masquer le clavier

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 vers 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
}

L'astuce se trouve dans la partie "keyboardWillShow" qui reçoit des appels à chaque fois que "QuickType Suggestion Bar" est développée ou réduite. 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 partie "barre QuickType").

A la fin n'oubliez pas de retirer les observateurs

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

3

Ce qui suit est une solution simple, dans laquelle le champ de texte a une contrainte le liant au guide de mise en page 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

Eh bien, je pense que je suis 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 des champs de nom d'utilisateur et de mot de passe. Au lieu de modifier la coordonnée y de la vue, j'enregistre la valeur de contrainte d'origine dans une variable et de changer la constante de la contrainte en une certaine valeur, puis à nouveau après le rejet du clavier, je configure la contrainte sur celle d'origine. De cette façon, il évite le problème de la réponse de Saqib (la vue continue de monter et ne s'arrête pas). Voici 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
  }

Dans la méthode keyboardWillShow , vérifiez la condition si self.centerYConstraint.constant == self.originalCenterYConstraint a alors une ligne de code entre cette condition. OriginalCenterYContraint est la valeur d'origine de centerYContraint que je stocke dans viewdidload. Cela a fonctionné pour moi.
Sashi

3

Réponse Swift 4.x, fusion des réponses de @Joseph Lord et @Isuru. bottomConstraintrepré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)
    }
}

2

J'ai fait de la manière suivante:

Ceci est utile lorsque la vue d'ensemble du champ de texte est affichée

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
    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

    }

1
Utilisez le code ci-dessus pour déplacer le champ de texte au-dessus du clavier dans swift 2.2, cela fonctionnera très bien. j'espère que cela aidera quelqu'un.
Kamalkumar.E

1

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

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 comme un charme. Je veux d'abord clarifier quelques points sur certaines des solutions mentionnées ci-dessus.

  1. Dans mon cas, IQkeyboardmanager ne fonctionnait que lorsqu'aucune disposition automatique n'était appliquée sur les éléments, si elle est appliquée, le gestionnaire IQkeyboard ne fonctionnera pas comme nous le pensons.
  2. Même chose avec un mouvement ascendant de self.view.
  3. j'ai écrit un en-tête objectif c avec un support rapide pour pousser UITexfield vers le haut lorsque l'utilisateur clique dessus, résolvant le problème du clavier couvrant l'UITextfield: https://github.com/coolvasanth/smart_keyboard .
  4. Celui qui a un niveau intermédiaire ou supérieur dans le développement d'applications iOS peut facilement comprendre le référentiel et l'implémenter. Bonne chance

1

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

1) Créez un ViewController commun qui est é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éez 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
}

}


Pour une raison quelconque, je rencontrais un problème dans la fonction keyboardWillShow, la taille du clavier devenait incorrecte après la première bascule du clavier (la première bascule a un cadre correct). J'ai corrigé cela en le changeant pour protéger let userInfo = notification.userInfo else {return} guard let keyboardSize = userInfo [UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {return} let keyboardFrame = keyboardSize.cgRectValue if self.view.frame.origin.y == 0 {self.view.frame.origin.y - = getMoveableDistance (keyboarHeight: keyboardFrame.height)}. J'espère que cela vous aidera si quelqu'un a le même problème :)
Youstanzr

1

Très simple et pas besoin de coder plus. Ajoutez simplement pod 'IQKeyboardManagerSwift'votre podfile, et dans votre AppDelegatepage ajoutez le code ci-dessous.

import IQKeyboardManagerSwift

et dans le didFinishLaunchingWithOptions()type de méthode

IQKeyboardManager.shared.enable = true

c'est ça. consultez ce lien vidéo pour une meilleure compréhension https://youtu.be/eOM94K1ZWN8 J'espère que cela vous aidera.


Cela fonctionne-t-il pour TextView et comment puis-je changer le titre de la touche retour "Terminé"?
tdt kien

Goto: - "IQKeyboardManager.m" Remplacez cette ligne (ligne n ° 968): - [textField addDoneOnKeyboardWithTarget: auto-action: @selector (doneAction :) shouldShowPlaceholder: _shouldShowTextFieldPlaceholder] par ceci: - [textField addRightButtonOnKeyboardWithText: @ " auto-action: @selector (doneAction :) shouldShowPlaceholder: _shouldShowTextFieldPlaceholder]; Et je n'ai pas encore essayé pour la visualisation de texte, j'espère que cela vous aidera.
Raghib Arshi

1

Code complet pour la gestion du clavier.

        override func viewWillAppear(_ animated: Bool) {
            NotificationCenter.default.addObserver(self, selector: #selector(StoryMediaVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(StoryMediaVC.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
        }
        override func viewWillDisappear(_ animated: Bool) {
            NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
            NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
        }
        @objc func keyboardWillShow(notification: NSNotification) {
            guard let userInfo = notification.userInfo else {return}
            guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {return}
            let keyboardFrame = keyboardSize.cgRectValue

            if self.view.bounds.origin.y == 0{
                self.view.bounds.origin.y += keyboardFrame.height
            }
        }


        @objc func keyboardWillHide(notification: NSNotification) {
            if self.view.bounds.origin.y != 0 {
                self.view.bounds.origin.y = 0
            }
        }

0

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

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

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

Remarque: J'utilisais un UITableView

Solution référencée @ keyboard-content-offset qui a été entièrement écrite dans l'objectif C, la solution ci-dessous est Swift propre.

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 de l'objet de notification, qui stocke tous les objets supplémentaires que notre récepteur pourrait utiliser.

À partir de ce dictionnaire, nous pouvons obtenir l'objet CGRect décrivant le cadre du clavier en utilisant la clé UIKeyboardFrameBeginUserInfoKey.

Appliquer l'encart 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;
    }
}

Restaurer 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
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)
    }
}

entrez la description de l'image ici


0

La solution Swift 4 que j'utilise prend la taille du clavier. Remplacez serverStatusStackViewpar 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)
}

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.