Cara mendeteksi saat keyboard ditampilkan dan disembunyikan

Jawaban:

166

Dalam metode ViewDidLoad kelas Anda, siapkan untuk mendengarkan pesan tentang keyboard:

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

Kemudian dalam metode yang Anda tentukan (dalam kasus ini keyboardDidShowdan keyboardDidHide) Anda dapat melakukan sesuatu tentangnya:

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

- (void)keyboardDidHide: (NSNotification *) notif{
    // Do something here
}
Matthew Frederick
sumber
Tidak bekerja jika Anda tab melalui bidang. Bertanya-tanya apa solusi untuk itu dan apakah Anda bahkan dapat menggunakan iPad yang sebenarnya?
i--
@apprentice Maksud Anda bahwa keyboard tidak muncul jika Anda melakukan tab?
Matthew Frederick
jika ada bidang yang masih tertutup oleh keyboard di bawah yang memiliki fokus, tampilan akan tetap berada di tab karena pemberitahuan hanya dikirim saat papan ketik meluncur ke atas
i--
3
@apprentice Anda harus mengelolanya dengan tangan, menggeser tampilan gulir berdasarkan setiap bidang teks menjadi aktif, masalah yang berbeda daripada mengetahui kapan keyboard muncul. Buat pengontrol tampilan Anda a UITextFieldDelegate, lalu terapkan textFieldShouldReturn:metode tersebut. Anda akan mendapatkan yang textFieldbaru saja dimasukkan sebagai argumen, yang dapat Anda bandingkan dengan bidang teks Anda sendiri dan gulir scrollViewsehingga bidang teks yang sesuai ditampilkan.
Matthew Frederick
95

Anda mungkin hanya perlu addObservermasuk viewDidLoad. Namun addObservermasuk viewWillAppeardan removeObservermasuk viewWillDisappearmencegah kerusakan langka yang terjadi saat Anda mengubah pandangan.

Swift 4.2.0

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 dan 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 yang lebih tua

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
sumber
9
Jika Anda menghapus pengamat Anda di viewWillDisappear ... Anda harus menambahkannya ke viewWillAppear, bukan viewDidLoad.
FouZ
Benar, silakan edit jawabannya. Saya akan menerimanya
Esqarrouth
@FouZ lebih baik menghapus pengamat dari deinitseperti ini:deinit { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) }
Crashalot
Di Swift 3, blok kode deinit di atas adalah seperti: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 tidak berjalan sampai Anda menutup vc. jadi jika Anda menampilkan vc lain di atas vc ini, ia masih akan menerima notifikasi. Saya yakin tujuannya adalah untuk hanya mendengarkan pemberitahuan ini sementara vc ini terlihat sehingga menambahkannya di viewdidappear dan menghapusnya di viewdiddissapear tampaknya lebih baik bagi saya.
Pochi
19

Cepat 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
sumber
9

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

Selanjutnya, menambahkan metode untuk berhenti mendengarkan pemberitahuan ketika kehidupan objek berakhir: -

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
sumber
The +=tampaknya membuat insets mendapatkan lebih besar dan lebih besar.
Wez
Saya rasa fungsi adjustKeyboardShow adalah fungsi yang dibuat dengan sangat baik. Terima kasih.
pengembang hong
pada nama pemberitahuan Swift 5 adalah UIResponder.keyboardWillShowNotificationdan UIResponder.keyboardWillHideNotification, dan tombol info keyboard adalah UIResponder.keyboardFrameBeginUserInfoKey.
CodeBrew
5

Cepat - 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
sumber
4

Lihat bagian Mengelola Keyboard dari "Teks, Web, dan Panduan Pemrograman Mengedit" untuk informasi tentang pelacakan keyboard yang ditampilkan atau disembunyikan, dan cara menampilkan / menutupnya secara manual.

Justin Spahr-Summers
sumber
4

Anda ingin mendaftarkan diri Anda untuk 2 pemberitahuan keyboard:

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

Posting bagus tentang cara menyesuaikan TextField Anda ke keyboard - http://iosdevelopertips.com/user-interface/adjust-textfield-hidden-by-keyboard.html

ChrisInTX
sumber
4

Di Swift 4.2, nama notifikasi telah dipindahkan ke namespace yang berbeda. Jadi sekarang

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

Cepat 5

Ada jawaban di atas benar. Meskipun saya lebih suka membuat pembantu untuk menyelesaikan file notification's observers.

Keuntungan:

  1. Anda tidak perlu mengulang setiap kali menangani perilaku keyboard.
  2. Anda dapat memperpanjang notifikasi lain dengan mengimplementasikan nilai enum lainnya
  3. Ini berguna ketika Anda harus berurusan dengan keyboard di beberapa pengontrol.

Kode sampel:

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

Cara Penggunaan:

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

Cepat 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
sumber
1

Jika Anda memiliki lebih dari satu UITextField dan Anda perlu melakukan sesuatu ketika (atau sebelum) keyboard muncul atau menghilang, Anda dapat menerapkan pendekatan ini.

Tambahkan UITextFieldDelegateke kelas Anda. Tetapkan penghitung bilangan bulat, katakanlah:

NSInteger editCounter; 

Setel penghitung ini ke nol di suatu tempat viewDidLoad. Kemudian, terapkan textFieldShouldBeginEditingdan textFieldShouldEndEditingdelegasikan metode.

Yang pertama tambahkan 1 ke editCounter. Jika nilai editCounter menjadi 1 - ini berarti keyboard akan muncul (jika Anda mengembalikan YA). Jika editCounter> 1 - ini berarti keyboard sudah terlihat dan UITextField lain memegang fokus.

Dalam textFieldShouldEndEditingkurangi 1 dari editCounter. Jika Anda mendapatkan nol - keyboard akan ditutup, jika tidak maka akan tetap ada di layar.

pengguna2248258
sumber
0

Anda dapat menggunakan perpustakaan KBKeyboardObserver . Ini berisi beberapa contoh dan menyediakan antarmuka yang sederhana.

kam800
sumber
0

Jadi ah, inilah jawaban sebenarnya sekarang.

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() },
        ]
    }
}
bersisik
sumber