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


Ответы:


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

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
}

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

}


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


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. Если вы получите ноль - клавиатура будет закрыта, в противном случае она останется на экране.


0

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



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() },
        ]
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.