Comment détecter quand le clavier est affiché et masqué

Réponses:

166

Dans la méthode ViewDidLoad de votre classe configurée pour écouter les messages sur le clavier:

// Listen for keyboard appearances and disappearances
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(keyboardDidShow:)
                                             name:UIKeyboardDidShowNotification
                                           object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardDidHide:)
                                             name:UIKeyboardDidHideNotification
                                           object:nil];

Ensuite, dans les méthodes que vous spécifiez (dans ce cas keyboardDidShowet keyboardDidHide), vous pouvez faire quelque chose à ce sujet:

- (void)keyboardDidShow: (NSNotification *) notif{
    // Do something here
}

- (void)keyboardDidHide: (NSNotification *) notif{
    // Do something here
}
Matthieu Frederick
la source
Ne fonctionne pas si vous passez par des champs. Vous vous demandez quelle serait la solution pour cela et si vous pouvez même consulter un iPad réel?
i--
@apprentice Voulez-vous dire que le clavier ne s'affiche pas si vous tabulez?
Matthew Frederick
s'il y a des champs encore couverts par le clavier sous celui avec le focus, la vue restera toujours sur l'onglet en raison de l'envoi de la notification uniquement au moment où le clavier glisse vers le haut
i--
3
@apprenti Vous devez gérer cela à la main, en faisant glisser la vue de défilement en fonction de l'activation de chaque champ de texte, un problème différent de celui de savoir quand le clavier apparaît. Faites de votre contrôleur de vue un UITextFieldDelegate, puis implémentez la textFieldShouldReturn:méthode. Vous obtiendrez le textFieldjuste entré comme argument, que vous pourrez comparer à vos propres textFields et faire défiler le scrollViewafin que le textField approprié soit affiché.
Matthew Frederick
95

Vous aurez juste besoin addObserverde viewDidLoad. Mais avoir addObserverin viewWillAppearet removeObserverin viewWillDisappearempêche les rares plantages qui se produisent lorsque vous changez de vue.

Swift 4.2

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear), name: UIResponder.keyboardWillHideNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear), name: UIResponder.keyboardWillShowNotification, object: nil)
}

@objc func keyboardWillAppear() {
    //Do something here
}

@objc func keyboardWillDisappear() {
    //Do something here
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

Swift 3 et 4

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear), name: Notification.Name.UIKeyboardWillHide, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear), name: Notification.Name.UIKeyboardWillShow, object: nil)
}

@objc func keyboardWillAppear() {
    //Do something here
}

@objc func keyboardWillDisappear() {
    //Do something here
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}

Swift plus âgé

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

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

func keyboardWillAppear(notification: NSNotification){
    // Do something here
}

func keyboardWillDisappear(notification: NSNotification){
    // Do something here
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}
Esqarrouth
la source
9
Si vous supprimez votre observateur sur viewWillDisappear ... vous devez l'ajouter dans viewWillAppear au lieu de viewDidLoad.
FouZ
C'est vrai, n'hésitez pas à modifier la réponse. Je vais l'accepter
Esqarrouth
@FouZ vaut-il mieux supprimer les observateurs de deinitcomme ça:deinit { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) }
Crashalot
Dans Swift 3, le bloc de code deinit ci-dessus est comme:deinit { NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) }
Md. Najmul Hasan
@Crashalot le deinit ne s'exécute pas tant que vous n'avez pas rejeté le vc. donc si vous présentez un autre vc en plus de celui-ci, il recevra toujours les notifications. Je pense que le but est d'écouter uniquement ces notifications pendant que ce vc est visible, donc l'ajouter sur viewdidappear et le supprimer sur viewdiddissapear me semble préférable.
Pochi
19

Swift 3:

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: NSNotification){
    // Do something here
}

func keyboardWillHide(_ notification: NSNotification){
    // Do something here
}
dichen
la source
9

Swift 4:

  NotificationCenter.default.addObserver( self, selector: #selector(ControllerClassName.keyboardWillShow(_:)),
  name: Notification.Name.UIKeyboardWillShow,
  object: nil)
  NotificationCenter.default.addObserver(self, selector: #selector(ControllerClassName.keyboardWillHide(_:)),
  name: Notification.Name.UIKeyboardWillHide,
  object: nil)

Ensuite, ajout d'une méthode pour arrêter d'écouter les notifications lorsque la vie de l'objet se termine: -

Then add the promised methods from above to the view controller:
deinit {
  NotificationCenter.default.removeObserver(self)
}
func adjustKeyboardShow(_ open: Bool, notification: Notification) {
  let userInfo = notification.userInfo ?? [:]
  let keyboardFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
  let height = (keyboardFrame.height + 20) * (open ? 1 : -1)
  scrollView.contentInset.bottom += height
  scrollView.scrollIndicatorInsets.bottom += height
}

@objc func keyboardWillShow(_ notification: Notification) {
  adjustKeyboardShow(true, notification: notification)
}
@objc func keyboardWillHide(_ notification: Notification) {
  adjustKeyboardShow(false, notification: notification)
}
Gurjinder Singh
la source
Le +=semble rendre les inserts de plus en plus grands.
Wez
Je pense que la fonction AdjustKeyboardShow est une fonction très bien conçue. Je vous remercie.
hong developer
à partir de Swift 5, le nom de la notification est UIResponder.keyboardWillShowNotificationet UIResponder.keyboardWillHideNotification, et la touche d'information du clavier est UIResponder.keyboardFrameBeginUserInfoKey.
CodeBrew
5

Rapide - 4

override func viewWillAppear(_ animated: Bool) {
   super.viewWillAppear(animated)
   addKeyBoardListener()
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self) //remove observer
}

func addKeyBoardListener() {
    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);
}

@objc func keyboardWillShow(_ notification: Notification) {

}

@objc func keyboardWillHide(_ notification: Notification) {

}
Rahul
la source
4

Consultez la section Gestion du clavier du «Guide de programmation de texte, Web et édition» pour obtenir des informations sur le suivi du clavier affiché ou masqué et comment l'afficher / le supprimer manuellement.

Justin Spahr-Summers
la source
4

Vous voudrez vous inscrire pour les 2 notifications clavier:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name: UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (keyboardDidHide:) name: UIKeyboardDidHideNotification object:nil];

Excellent article sur la façon d'ajuster votre TextField au clavier - http://iosdevelopertips.com/user-interface/adjust-textfield-hidden-by-keyboard.html

ChrisInTX
la source
4

Dans Swift 4.2, les noms de notification ont été déplacés vers un espace de noms différent. Alors maintenant c'est

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    addKeyboardListeners()
}


override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self)
}


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

@objc private extension WhateverTheClassNameIs {

    func keyboardWillShow(_ notification: Notification) {
        // Do something here.
    }

    func keyboardWillHide(_ notification: Notification) {
        // Do something here.
    }
}
Sebbo
la source
3

Swift 5

Les réponses ci-dessus sont correctes. Bien que je préfère créer une aide pour conclure le fichier notification's observers.

Le bénéfice:

  1. Vous n'avez pas à répéter chaque fois que vous gérez les comportements du clavier.
  2. Vous pouvez étendre une autre notification en implémentant une autre valeur enum
  3. C'est utile lorsque vous devez gérer le clavier dans plusieurs contrôleurs.

Exemple de code:

extension KeyboardHelper {
    enum Animation {
        case keyboardWillShow
        case keyboardWillHide
    }

    typealias HandleBlock = (_ animation: Animation, _ keyboardFrame: CGRect, _ duration: TimeInterval) -> Void
}

final class KeyboardHelper {
    private let handleBlock: HandleBlock

    init(handleBlock: @escaping HandleBlock) {
        self.handleBlock = handleBlock
        setupNotification()
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    private func setupNotification() {
        _ = NotificationCenter.default
            .addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { [weak self] notification in
                self?.handle(animation: .keyboardWillShow, notification: notification)
            }

        _ = NotificationCenter.default
            .addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { [weak self] notification in
                self?.handle(animation: .keyboardWillHide, notification: notification)
            }
    }

    private func handle(animation: Animation, notification: Notification) {
        guard let userInfo = notification.userInfo,
            let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
            let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double
        else { return }

        handleBlock(animation, keyboardFrame, duration)
    }
}

Comment utiliser:

private var keyboardHelper: KeyboardHelper?
...

override func viewDidLoad() {
   ...
   keyboardHelper = KeyboardHelper { [unowned self] animation, keyboardFrame, duration in
        switch animation {
        case .keyboardWillShow:
            print("keyboard will show")
        case .keyboardWillHide:
            print("keyboard will hide")
        }
    }

}

nahung89
la source
2

Swift 4 -dd 20 october 2017

override func viewDidLoad() {
    [..]

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(_:)), name: Notification.Name.UIKeyboardWillHide, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(_:)), name: Notification.Name.UIKeyboardWillShow, object: nil)
}

@objc func keyboardWillAppear(_ notification: NSNotification) {
    if let userInfo = notification.userInfo, 
       let keyboardFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue).cgRectValue {
           let inset = keyboardFrame.height // if scrollView is not aligned to bottom of screen, subtract offset
           scrollView.contentInset.bottom = inset
           scrollView.scrollIndicatorInsets.bottom = inset
    }
}

@objc func keyboardWillDisappear(_ notification: NSNotification) {
    scrollView.contentInset.bottom = 0
    scrollView.scrollIndicatorInsets.bottom = 0
}

deinit {
    NotificationCenter.default.removeObserver(self)
}
dOM
la source
1

Si vous en avez plusieurs UITextFieldet que vous devez faire quelque chose lorsque (ou avant) le clavier apparaît ou disparaît, vous pouvez implémenter cette approche.

Ajoutez UITextFieldDelegateà votre classe. Attribuez un compteur entier, disons:

NSInteger editCounter; 

Mettez ce compteur à zéro quelque part dans viewDidLoad. Ensuite, implémentez textFieldShouldBeginEditinget textFieldShouldEndEditingdéléguez des méthodes.

Dans le premier, ajoutez 1 à editCounter. Si la valeur de editCounter devient 1 - cela signifie que le clavier apparaîtra (au cas où vous retournez YES). Si editCounter> 1 - cela signifie que le clavier est déjà visible et qu'un autre UITextField détient le focus.

En textFieldShouldEndEditingsoustrayez 1 à editCounter. Si vous obtenez zéro, le clavier sera ignoré, sinon il restera à l'écran.

user2248258
la source
0

Vous pouvez utiliser la bibliothèque KBKeyboardObserver . Il contient quelques exemples et fournit une interface simple.

kam800
la source
0

Alors ah, c'est la vraie réponse maintenant.

import Combine


class MrEnvironmentObject {
    /// Bind into yr SwiftUI views
    @Published public var isKeyboardShowing: Bool = false

    /// Keep 'em from deallocatin'
    var subscribers: [AnyCancellable]? = nil

    /// Adds certain Combine subscribers that will handle updating the
    ///  `isKeyboardShowing` property 
    ///
    /// - Parameter host: the UIHostingController of your views. 
    func setupSubscribers<V: View>(
        host: inout UIHostingController<V>
    ) {
        subscribers = [
            NotificationCenter
                .default
                .publisher(for: UIResponder.keyboardWillShowNotification)
                .sink { [weak self] _ in
                    self?.isKeyboardShowing = true
                },
            NotificationCenter
                .default
                .publisher(for: UIResponder.keyboardWillHideNotification)
                .sink { [weak self, weak host] _ in
                    self?.isKeyboardShowing = false
                    // Hidden gem, ask me how I know:
                    UIAccessibility.post(
                        notification: .layoutChanged, 
                        argument: host
                    )
                },
            // ...
            Profit
                .sink { [weak self] profit in profit() },
        ]
    }
}
squameux
la source