Cách phát hiện khi bàn phím được hiển thị và ẩn


Câu trả lời:


166

Trong phương thức ViewDidLoad của lớp bạn được thiết lập để lắng nghe thông báo về bàn phím:

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

Sau đó, trong các phương thức bạn chỉ định (trong trường hợp này keyboardDidShowkeyboardDidHide), bạn có thể làm gì đó với nó:

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

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

Không hoạt động nếu bạn tab qua các trường. Tự hỏi giải pháp cho điều đó sẽ là gì và nếu bạn thậm chí có thể lướt qua một chiếc iPad thực tế?
tôi--

@apprentice Ý của bạn là bàn phím không hiển thị nếu bạn tab?
Matthew Frederick

nếu có các trường vẫn bị bàn phím che bên dưới trường có tiêu điểm, chế độ xem sẽ vẫn nằm trên tab do thông báo chỉ được gửi vào lúc bàn phím trượt lên
i--

3
@apprentice Bạn phải quản lý điều đó bằng tay, trượt chế độ xem cuộn xung quanh dựa trên mỗi trường văn bản đang hoạt động, một vấn đề khác với việc biết khi nào bàn phím xuất hiện. Đặt bộ điều khiển chế độ xem của bạn thành UITextFieldDelegate, sau đó triển khai textFieldShouldReturn:phương thức. Bạn sẽ nhận được đối số textFieldvừa nhập dưới dạng đối số, bạn có thể so sánh với Trường văn bản của riêng mình và cuộn scrollViewđể Trường văn bản thích hợp hiển thị.
Matthew Frederick

94

Bạn có thể chỉ cần addObservervào viewDidLoad. Nhưng có addObserverviewWillAppearremoveObservertrong viewWillDisappearngăn ngừa tai nạn hiếm xảy ra khi bạn đang thay đổi quan điểm của bạn.

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 và 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 cũ hơn

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
Nếu bạn xóa trình quan sát của mình trên viewWillDisappear ... bạn nên thêm nó vào viewWillAppear thay vì viewDidLoad.
FouZ

Đó là sự thật, vui lòng chỉnh sửa câu trả lời. Tôi sẽ chấp nhận nó
Esqarrouth

@FouZ có tốt hơn không nếu xóa những người quan sát deinitnhư thế này:deinit { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) }
Crashalot

Trong Swift 3, khối mã deinit ở trên giống như: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 không chạy cho đến khi bạn loại bỏ vc. vì vậy nếu bạn trình bày một vc khác trên đầu trang này, nó vẫn sẽ nhận được thông báo. Tôi tin rằng mục đích là chỉ nghe thông báo này trong khi vc này hiển thị, vì vậy việc thêm nó trên viewdidappear và xóa nó trên viewdiddissapear có vẻ tốt hơn đối với tôi.
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)

Tiếp theo, thêm phương thức ngừng nghe thông báo khi vòng đời của đối tượng kết thúc: -

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

Các +=dường như làm cho insets có được lớn hơn và lớn hơn.
Wez,

Tôi nghĩ rằng chức năng AdjustKeyboardShow là một chức năng rất tốt. Cảm ơn bạn.
hong developer

kể từ tên thông báo Swift 5 là UIResponder.keyboardWillShowNotificationUIResponder.keyboardWillHideNotification, và phím thông tin bàn phím là UIResponder.keyboardFrameBeginUserInfoKey.
CodeBrew

5

Swift - 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) {

}

4

Hãy xem phần Quản lý Bàn phím của "Hướng dẫn Lập trình Văn bản, Web và Chỉnh sửa" để biết thông tin về cách theo dõi bàn phím được hiển thị hoặc ẩn và cách hiển thị / loại bỏ bàn phím theo cách thủ công.


4

Bạn sẽ muốn tự mình đăng ký 2 thông báo bàn phím:

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

Bài đăng tuyệt vời về cách điều chỉnh TextField của bạn thành bàn phím - http://iosdevelopertips.com/user-interface/adjust-textfield-hiested-by-keyboard.html


4

Trong Swift 4.2, tên thông báo đã chuyển sang một vùng tên khác. Vì vậy, bây giờ nó

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

3

Swift 5

Có câu trả lời ở trên là chính xác. Mặc dù tôi muốn tạo một người trợ giúp để kết thúc notification's observers.

Lợi ích:

  1. Bạn không phải lặp lại mỗi khi xử lý các hành vi trên bàn phím.
  2. Bạn có thể mở rộng thông báo khác bằng cách triển khai giá trị enum khác
  3. Nó hữu ích khi bạn phải xử lý bàn phím trong một số bộ điều khiển.

Mã mẫu:

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ách sử dụng:

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

}


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

Nếu bạn có nhiều hơn một UITextFieldphím và bạn cần phải làm gì đó khi (hoặc trước) bàn phím xuất hiện hoặc biến mất, bạn có thể thực hiện phương pháp này.

Thêm UITextFieldDelegatevào lớp học của bạn. Gán bộ đếm số nguyên, giả sử:

NSInteger editCounter; 

Đặt bộ đếm này thành 0 ở đâu đó trong viewDidLoad. Sau đó, thực hiện textFieldShouldBeginEditingtextFieldShouldEndEditingủy quyền các phương thức.

Trong phần đầu tiên, hãy thêm 1 vào editCounter. Nếu giá trị của editCounter trở thành 1 - điều này có nghĩa là bàn phím đó sẽ xuất hiện (trong trường hợp nếu bạn trả về YES). Nếu editCounter> 1 - điều này có nghĩa là bàn phím đó đã hiển thị và một UITextField khác giữ tiêu điểm.

Trong textFieldShouldEndEditingtrừ 1 từ editCounter. Nếu bạn nhận được số 0 - bàn phím sẽ bị loại bỏ, nếu không bàn phím sẽ vẫn còn trên màn hình.




0

Vì vậy, đây là câu trả lời thực sự bây giờ.

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() },
        ]
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.