Jak wykryć, kiedy klawiatura jest wyświetlana i ukryta


Odpowiedzi:


168

W metodzie ViewDidLoad swojej klasy skonfigurowanej do nasłuchiwania komunikatów dotyczących klawiatury:

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

Następnie w metodach, które określisz (w tym przypadku keyboardDidShowi keyboardDidHide) możesz coś z tym zrobić:

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

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

Nie działa, jeśli przechodzisz przez pola. Zastanawiasz się, jakie byłoby rozwiązanie tego problemu i czy możesz nawet przechodzić przez kartę na prawdziwym iPadzie?
I--

@apprentice Czy masz na myśli to, że klawiatura nie wyświetla się, gdy używasz tabulacji?
Matthew Frederick

jeśli są jeszcze pola zakryte klawiaturą poniżej tej z fokusem, widok pozostanie na karcie z powodu wysłania powiadomienia tylko w momencie, gdy klawiatura
przesunie się w

3
@apprentice Musisz sobie z tym poradzić ręcznie, przesuwając widok przewijania w zależności od tego, czy każde pole tekstowe staje się aktywne, inny problem niż wiedza o pojawieniu się klawiatury. Ustaw kontroler widoku jako UITextFieldDelegate, a następnie zaimplementuj textFieldShouldReturn:metodę. Otrzymasz textFieldwłaśnie wprowadzony argument jako argument, który możesz porównać z własnymi polami textField i przewinąć scrollView, aby wyświetlić odpowiednie pole tekstowe.
Matthew Frederick

95

Może po prostu trzeba addObserversię viewDidLoad. Ale mając addObserverw viewWillAppeari removeObserverwviewWillDisappear zapobiega rzadkich wypadków, które się dzieje, gdy zmieniają swój pogląd.

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

Starszy Szybki

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
Jeśli usuniesz swojego obserwatora w viewWillDisappear ... powinieneś dodać go do viewWillAppear zamiast viewDidLoad.
FouZ

To prawda, nie krępuj się edytować odpowiedzi. Przyjmę to
Esqarrouth

@FouZ czy lepiej jest usunąć obserwatorów z deinittego:deinit { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) }
Crashalot

W Swift 3 powyższy blok kodu deinit wygląda następująco: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 deinit nie działa, dopóki nie odrzucisz vc. więc jeśli przedstawisz inny vc na tym, nadal będzie otrzymywać powiadomienia. Uważam, że celem jest odsłuchiwanie tych powiadomień tylko wtedy, gdy ten vc jest widoczny, więc dodanie go w widoku viewdidappear i usunięcie go w viewdiddissapear wydaje mi się lepsze.
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)

Następnie dodajemy metodę zatrzymania nasłuchiwania powiadomień, gdy kończy się żywotność obiektu: -

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

+=Wydaje się uczynić Wstawki uzyskać większe.
Wez

Myślę, że funkcja adjustKeyboardShow to bardzo dobrze wykonana funkcja. Dziękuję Ci.
hong programista

od Swift 5 nazwa powiadomienia to UIResponder.keyboardWillShowNotificationi UIResponder.keyboardWillHideNotification, a klawisz informacyjny na klawiaturze to UIResponder.keyboardFrameBeginUserInfoKey.
CodeBrew

5

Szybki - 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

W Swift 4.2 nazwy powiadomień zostały przeniesione do innej przestrzeni nazw. Więc teraz jest

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

Szybki 5

Powyższe odpowiedzi są poprawne. Chociaż wolałbym utworzyć pomocnika, aby zakończyć notification's observers.

Korzyść:

  1. Nie musisz powtarzać za każdym razem, gdy zajmujesz się zachowaniami klawiatury.
  2. Możesz rozszerzyć inne powiadomienie, implementując inną wartość wyliczenia
  3. Przydaje się, gdy masz do czynienia z klawiaturą w kilku kontrolerach.

Przykładowy kod:

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

Jak używać:

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

Będziesz chciał zarejestrować się na 2 powiadomienia z klawiatury:

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

Świetny post o tym, jak dostosować swoje TextField do klawiatury - 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

Jeśli masz więcej niż jeden UITextField i musisz coś zrobić, gdy (lub wcześniej) klawiatura pojawia się lub znika, możesz zastosować to podejście.

Dodaj UITextFieldDelegatedo swojej klasy. Przypisz licznik całkowity, powiedzmy:

NSInteger editCounter; 

Ustaw ten licznik na zero gdzieś w viewDidLoad. Następnie zaimplementuj textFieldShouldBeginEditingi textFieldShouldEndEditingdeleguj metody.

W pierwszym dodaj 1 do editCounter. Jeśli wartość editCounter wynosi 1 - oznacza to, że pojawi się klawiatura (w przypadku, gdy zwrócisz TAK). Jeśli editCounter> 1 - oznacza to, że klawiatura jest już widoczna i inny UITextField utrzymuje fokus.

W textFieldShouldEndEditingodejmij 1 od editCounter. Jeśli uzyskasz zero - klawiatura zostanie odrzucona, w przeciwnym razie pozostanie na ekranie.




0

Więc ach, to jest teraz prawdziwa odpowiedź.

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() },
        ]
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.