Как определить, когда клавиатура отображается и скрывается

Ответы:

168

В методе ViewDidLoad вашего класса, настроенном для прослушивания сообщений о клавиатуре:

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

Затем в указанных вами методах (в данном случае keyboardDidShowи keyboardDidHide) вы можете что-то с этим сделать:

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

- (void)keyboardDidHide: (NSNotification *) notif{
    // Do something here
}
Мэтью Фредерик
источник
Не работает при переходе через поля табуляции. Хотите знать, какое решение для этого будет, и сможете ли вы даже использовать табуляцию на реальном iPad?
i--
@apprentice Вы имеете в виду, что клавиатура не отображается при переходе по табуляции?
Мэтью Фредерик
если есть поля, все еще покрытые клавиатурой под тем, что находится в фокусе, представление останется на вкладке, так как уведомление отправляется только в тот момент, когда клавиатура
сдвигается
3
@apprentice Вы должны управлять этим вручную, перемещая прокрутку в зависимости от того, становится ли каждое текстовое поле активным. Это другая проблема, чем знать, когда появляется клавиатура. Сделайте свой контроллер представления значком UITextFieldDelegate, а затем реализуйте textFieldShouldReturn:метод. Вы получите textFieldтолько что введенный аргумент, который можно сравнить со своими собственными текстовыми полями и прокрутить, scrollViewчтобы отобразить соответствующее текстовое поле.
Мэтью Фредерик
95

Вы можете просто нужно addObserverв viewDidLoad. Но наличие addObserverin viewWillAppearи removeObserverin viewWillDisappearпредотвращает редкие сбои, которые случаются, когда вы меняете свое представление.

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

Старый Свифт

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
источник
9
Если вы удалите своего наблюдателя на viewWillDisappear ... вы должны добавить его в viewWillAppear вместо viewDidLoad.
FouZ
Это правда, смело редактируйте ответ. Я приму это
Esqarrouth
@FouZ неужели лучше удалить наблюдателей deinitвот так:deinit { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) }
Crashalot 07
В Swift 3 приведенный выше блок deinit { NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) }
деиницирующего
@Crashalot deinit не запускается, пока вы не закроете vc. поэтому, если вы представите еще один виртуальный компьютер поверх этого, он все равно будет получать уведомления. Я считаю, что цель состоит в том, чтобы слушать эти уведомления только тогда, когда этот vc виден, поэтому мне кажется лучше добавить его в viewdidappear и удалить его на viewdiddissapear.
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
источник
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)

Затем добавляем метод, позволяющий прекратить прослушивание уведомлений, когда жизнь объекта заканчивается: -

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)
}
Гурджиндер Сингх
источник
+=, Как представляется , сделать вставки получить больше и больше.
Wez
Я думаю, что функция adjustKeyboardShow - очень хорошо продуманная функция. Спасибо.
гоночный разработчик
в Swift 5 название уведомления - UIResponder.keyboardWillShowNotificationи UIResponder.keyboardWillHideNotification, а клавиша с информацией на клавиатуре - UIResponder.keyboardFrameBeginUserInfoKey.
CodeBrew
5

Стриж - 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) {

}
Рахул
источник
5

В Swift 4.2 имена уведомлений переместились в другое пространство имен. Итак, теперь это

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.
    }
}
Себбо
источник
5

Swift 5

Выше указаны правильные ответы. Хотя я бы предпочел создать помощник для завершения notification's observers.

Выгода:

  1. Вам не нужно повторять каждый раз, когда вы управляете поведением клавиатуры.
  2. Вы можете расширить другое уведомление, реализовав другое значение перечисления
  3. Это полезно, когда вам приходится иметь дело с клавиатурой в нескольких контроллерах.

Образец кода:

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

Как использовать:

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
источник
4

Ознакомьтесь с разделом « Управление клавиатурой » «Руководства по программированию для текста, Интернета и редактирования», чтобы получить информацию об отслеживании отображаемой или скрытой клавиатуры и о том, как отображать / закрывать ее вручную.

Джастин Спар-Саммерс
источник
4

Вы захотите зарегистрироваться для получения двух уведомлений с клавиатуры:

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

Отличный пост о том, как настроить TextField на клавиатуру - http://iosdevelopertips.com/user-interface/adjust-textfield-hidden-by-keyboard.html

ChrisInTX
источник
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)
}
ДОМ
источник
1

Если у вас больше одного UITextField и вам нужно что-то сделать, когда (или до того, как) клавиатура появится или исчезнет, ​​вы можете реализовать этот подход.

Добавьте UITextFieldDelegateв свой класс. Назначьте целочисленный счетчик, скажем:

NSInteger editCounter; 

Установите этот счетчик на ноль где-нибудь в viewDidLoad. Затем реализуйте textFieldShouldBeginEditingи textFieldShouldEndEditingделегируйте методы.

В первом добавьте 1 в editCounter. Если значение editCounter становится равным 1 - это означает, что появится клавиатура (в случае если вы вернете YES). Если editCounter> 1 - это означает, что клавиатура уже видна, а фокус находится в другом UITextField.

В textFieldShouldEndEditingвычитать 1 из editCounter. Если вы получите ноль - клавиатура будет закрыта, в противном случае она останется на экране.

user2248258
источник
0

Вы можете использовать библиотеку KBKeyboardObserver . Он содержит несколько примеров и предоставляет простой интерфейс.

кам800
источник
0

Так что теперь это настоящий ответ.

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() },
        ]
    }
}
чешуйчатый
источник