Cómo detectar cuándo se muestra y se oculta el teclado

Respuestas:

166

En el método ViewDidLoad de su clase configurado para escuchar mensajes sobre el 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];

Luego, en los métodos que especifique (en este caso keyboardDidShowy keyboardDidHide) puede hacer algo al respecto:

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

- (void)keyboardDidHide: (NSNotification *) notif{
    // Do something here
}
Matthew Frederick
fuente
No funciona si tabula a través de campos. Me pregunto cuál sería la solución para eso y si incluso puede usar la pestaña en un iPad real.
i--
@apprentice ¿Quiere decir que el teclado no se muestra si tabula?
Matthew Frederick
si todavía hay campos cubiertos por el teclado debajo del que tiene el foco, la vista permanecerá en la pestaña debido a que la notificación se envía solo en el momento en que el teclado se desliza hacia arriba
i--
3
@apprentice Tienes que administrar eso a mano, deslizando la vista de desplazamiento en función de cada campo de texto que se activa, un problema diferente al de saber cuándo aparece el teclado. Haga que su controlador de vista sea una UITextFieldDelegate, luego implemente el textFieldShouldReturn:método. Obtendrá el que textFieldacaba de ingresar como un argumento, que puede comparar con sus propios campos de texto y desplazarse scrollViewpara que se muestre el campo de texto apropiado.
Matthew Frederick
95

Simplemente tendrá addObserveren viewDidLoad. Pero tener addObserveradentro viewWillAppeary removeObserveradentro viewWillDisappearpreviene fallas raras que ocurren cuando cambia su vista.

Rápido 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 y 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 mayor

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
fuente
9
Si elimina su observador en viewWillDisappear ... debe agregarlo a viewWillAppear en lugar de viewDidLoad.
FouZ
Eso es cierto, no dude en editar la respuesta. Lo aceptaré
Esqarrouth
@FouZ es mejor eliminar a los observadores de deinitesta manera:deinit { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) }
Crashalot
En Swift 3, el bloque de código deinit anterior es 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 el deinit no se ejecuta hasta que descarta el vc. por lo que si presenta otro vc además de este, seguirá recibiendo las notificaciones. Creo que el propósito es solo escuchar estas notificaciones mientras este vc está visible, por lo que agregarlo en viewdidappear y eliminarlo en viewdiddissapear me parece mejor.
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
fuente
9

Rápido 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)

A continuación, agregue un método para dejar de escuchar las notificaciones cuando finalice la vida del objeto: -

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
fuente
El +=parece hacer que las inserciones sean cada vez más grandes.
Miércoles
Creo que la función adjustKeyboardShow es una función muy bien hecha. Gracias.
desarrollador de hong
a partir de Swift 5, el nombre de la notificación es UIResponder.keyboardWillShowNotificationy UIResponder.keyboardWillHideNotification, y la tecla de información del teclado es UIResponder.keyboardFrameBeginUserInfoKey.
CodeBrew
5

Rápido - 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
fuente
4

Consulte la sección Administración del teclado de la "Guía de programación de edición, edición y texto" para obtener información sobre cómo rastrear el teclado que se muestra u oculta, y cómo mostrarlo / descartarlo manualmente.

Justin Spahr-Summers
fuente
4

Querrá registrarse para las 2 notificaciones del teclado:

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

Excelente publicación sobre cómo ajustar su TextField al teclado: http://iosdevelopertips.com/user-interface/adjust-textfield-hidden-by-keyboard.html

ChrisInTX
fuente
4

En Swift 4.2, los nombres de las notificaciones se han movido a un espacio de nombres diferente. Entonces ahora es

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

Rápido 5

Las respuestas anteriores son correctas. Aunque preferiría crear un ayudante para terminar el notification's observers.

El beneficio:

  1. No tiene que repetir cada vez que maneja los comportamientos del teclado.
  2. Puede extender otra notificación implementando otro valor de enumeración
  3. Es útil cuando tienes que lidiar con el teclado en varios controladores.

Código de muestra:

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

Cómo utilizar:

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

Rápido 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
fuente
1

Si tiene más de uno UITextFieldy necesita hacer algo cuando (o antes) el teclado aparece o desaparece, puede implementar este enfoque.

Agregue UITextFieldDelegatea su clase. Asignar contador de enteros, digamos:

NSInteger editCounter; 

Ponga este contador a cero en algún lugar viewDidLoad. Luego, implemente textFieldShouldBeginEditingy textFieldShouldEndEditingdelegue métodos.

En el primero, agregue 1 para editCounter. Si el valor de editCounter se convierte en 1, esto significa que aparecerá el teclado (en caso de que devuelva YES). Si editCounter> 1, esto significa que el teclado ya está visible y otro UITextField mantiene el foco.

En textFieldShouldEndEditingrestar 1 de editCounter. Si obtiene cero, el teclado se cerrará; de lo contrario, permanecerá en la pantalla.

usuario2248258
fuente
0

Puede usar la biblioteca KBKeyboardObserver . Contiene algunos ejemplos y proporciona una interfaz sencilla.

kam800
fuente
0

Entonces, esta es la verdadera respuesta ahora.

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
fuente