Como detectar quando o teclado é mostrado e escondido

Respostas:

166

No método ViewDidLoad de sua classe, configure para ouvir mensagens sobre o teclado:

// 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];

Então, nos métodos que você especificar (neste caso keyboardDidShowe keyboardDidHide), você pode fazer algo a respeito:

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

- (void)keyboardDidHide: (NSNotification *) notif{
    // Do something here
}
Matthew Frederick
fonte
Não funciona se você tabular os campos. Gostaria de saber qual seria a solução para isso e se você pode usar a guia em um iPad real?
i--
@apprentice Quer dizer que o teclado não mostra se você usar a tecla tab?
Matthew Frederick de
se ainda houver campos cobertos pelo teclado abaixo daquele com o foco, a visualização permanecerá na guia devido à notificação sendo enviada apenas no momento em que o teclado deslizar para cima
i--
3
@apprentice Você tem que gerenciar isso manualmente, deslizando a exibição de rolagem com base na ativação de cada campo de texto, um problema diferente de saber quando o teclado aparece. Transforme seu controlador de visualização em um UITextFieldDelegate, em seguida, implemente o textFieldShouldReturn:método. Você obterá o que textFieldacabou de inserir como um argumento, que pode comparar com seus próprios textFields e rolar o scrollViewpara que o textField apropriado seja exibido.
Matthew Frederick,
94

Você só precisa addObserverentrar viewDidLoad. Mas tendo addObserverdentro viewWillAppeare removeObserverdentroviewWillDisappear evita travamentos raros que acontecem quando você muda sua visão.

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 e 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 mais velho

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
fonte
9
Se você remover seu observador em viewWillDisappear ... você deve adicioná-lo a viewWillAppear em vez de viewDidLoad.
FouZ
Isso é verdade, fique à vontade para editar a resposta. Eu vou aceitar
Esqarrouth
@FouZ é melhor remover os observadores deinitassim:deinit { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) }
Crashalot de
No Swift 3, o bloco de código definido acima é como: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 o deinit não roda até que você dispense o vc. então se você apresentar outro vc em cima deste ele ainda receberá as notificações. Acredito que o propósito é apenas ouvir essas notificações enquanto este vc estiver visível, então adicioná-lo no viewdidappear e removê-lo no viewdiddissapear parece melhor para mim.
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
fonte
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)

Em seguida, adicionando método para parar de ouvir notificações quando a vida útil do objeto terminar: -

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
fonte
O +=parece fazer as inserções ficarem cada vez maiores.
Wez
Acho que a função AdjustKeyboardShow é uma função muito bem feita. Obrigado.
desenvolvedor hong de
a partir do Swift 5, o nome da notificação é UIResponder.keyboardWillShowNotificatione UIResponder.keyboardWillHideNotification, e a tecla de informações do teclado é UIResponder.keyboardFrameBeginUserInfoKey.
CodeBrew
5

Swift - 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
fonte
4

Verifique a seção Gerenciando o Teclado do "Guia de Programação de Texto, Web e Edição" para obter informações sobre como rastrear o teclado que está sendo mostrado ou oculto e como exibi-lo / descartá-lo manualmente.

Justin Spahr-Summers
fonte
4

Você vai querer se registrar para as 2 notificações de teclado:

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

Excelente postagem sobre como ajustar seu TextField ao teclado - http://iosdevelopertips.com/user-interface/adjust-textfield-hidden-by-keyboard.html

ChrisInTX
fonte
4

No Swift 4.2, os nomes das notificações foram movidos para um namespace diferente. Então agora é

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

Swift 5

As respostas acima estão corretas. Embora eu prefira criar um auxiliar para finalizar o notification's observers.

O benefício:

  1. Você não precisa repetir cada vez que lidar com os comportamentos do teclado.
  2. Você pode estender outra notificação implementando outro valor enum
  3. É útil quando você precisa lidar com o teclado em vários controladores.

Código de amostra:

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

Como usar:

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

Se você tiver mais de um UITextFieldse precisar fazer algo quando (ou antes) do teclado aparecer ou desaparecer, você pode implementar esta abordagem.

Adicione UITextFieldDelegateà sua classe. Atribuir contador inteiro, digamos:

NSInteger editCounter; 

Defina este contador como zero em algum lugar viewDidLoad. Em seguida, implemente textFieldShouldBeginEditinge textFieldShouldEndEditingdelegue métodos.

No primeiro, adicione 1 a editCounter. Se o valor de editCounter se tornar 1 - isso significa que o teclado aparecerá (no caso, se você retornar YES). Se editCounter> 1 - significa que o teclado já está visível e outro UITextField mantém o foco.

Em textFieldShouldEndEditingsubtrair 1 editCounter. Se você obtiver zero - o teclado será descartado, caso contrário, permanecerá na tela.

user2248258
fonte
0

Você pode usar a biblioteca KBKeyboardObserver . Ele contém alguns exemplos e fornece uma interface simples.

Kam800
fonte
0

Então, ah, esta é a verdadeira resposta agora.

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() },
        ]
    }
}
escamoso
fonte