如何在Swift 3中编写键盘通知



我正在尝试将此代码更新为Swift 3:

NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)`

到目前为止,我刚刚尝试了编译器给出的自动更正。这会导致这样的代码:

let notificationCenter = NotificationCenter.default()
notificationCenter.addObserver(self, selector: Selector(("keyboardWillShow:")), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
notificationCenter.addObserver(self, selector: Selector(("keyboardWillHide:")), name: NSNotification.Name.UIKeyboardWillHide, object: nil)`

不幸的是,这并没有使我走得更远,导致了其他错误。

有人解决了这个问题吗?

请注意,我只是在尝试如何编写通知。我还没有试图修复通知功能。谢谢

swift 4.2 xcode 10(10l213o)

与Swift 3相比,主要更改在UIWindow.keyboardWillShowNotificationUIWindow.keyboardWillHideNotification

let notifier = NotificationCenter.default
notifier.addObserver(self,
                     selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification(_:)),
                     name: UIWindow.keyboardWillShowNotification,
                     object: nil)
notifier.addObserver(self,
                     selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification(_:)),
                     name: UIWindow.keyboardWillHideNotification,
                     object: nil)

@objc
func keyboardWillShowNotification(_ notification: NSNotification) {}
@objc
func keyboardWillHideNotification(_ notification: NSNotification) {}

swift 4

override func viewDidLoad() {
    super.viewDidLoad()   
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
     print("keyboardWillShow")
}
func keyboardWillHide(notification: NSNotification){
     print("keyboardWillHide")
}
deinit {
     NotificationCenter.default.removeObserver(self)
}

您还可以使用这些方法中的以下代码获取键盘信息。

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil) .      
@objc func keyboardWillChange(notification: NSNotification) {
     let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
     let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
     let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
     let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
     let deltaY = targetFrame.origin.y - curFrame.origin.y
 }

我通过编写类似的代码

来解决此问题
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)

swift 4.2 .UIKeyboardWillShow已更名为UIResponder.keyboardWillShowNotification.UIKeyboardWillHide被重命名为UIResponder.keyboardWillHideNotification

 NotificationCenter.default.addObserver(self, selector: #selector(NameOfSelector), name: UIResponder.keyboardWillShowNotification , object: nil)
 NotificationCenter.default.addObserver(self, selector: #selector(NameOfSelector), name: UIResponder.keyboardWillHideNotification , object: nil)
   @objc func NameOfSelector() {
       //Actions when notification is received
    }

您可以用类型检查的#selector(Class.method)对替换不弃用的字符串字面的Selector

let center = NotificationCenter.default
center.addObserver(self,
                   selector: #selector(keyboardWillShow(_:)),
                   name: .UIKeyboardWillShow,
                   object: nil)
center.addObserver(self,
                   selector: #selector(keyboardWillHide(_:)),
                   name: .UIKeyboardWillHide,
                   object: nil)

#selector语法要安全得多,因为Swift能够在编译时间检查指定方法实际上存在。

有关Swift Selectors的更多信息,请参见Rickster的详细答案。

swift 5.1 combine swiftui

@State var keyboardHeight: CGFloat = 0 // or @Published if one is in ViewModel: ObservableObject
private var cancellableSet: Set<AnyCancellable> = []
    
init() {
            
   let notificationCenter = NotificationCenter.default
        
   notificationCenter.publisher(for: UIWindow.keyboardWillShowNotification)
       .map {
             guard
                 let info = $0.userInfo,
                 let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
                 else { return 0 }
             return keyboardFrame.height
         }
         .assign(to: .keyboardHeight, on: self)
         .store(in: &cancellableSet)
        
     notificationCenter.publisher(for: UIWindow.keyboardDidHideNotification)
         .map { _ in 0 }
         .assign(to: .keyboardHeight, on: self)
         .store(in: &cancellableSet)
    }
    

在Swift 3.0

 override func viewDidLoad()
    {
        super.viewDidLoad()
 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)
}

keybord show和hide

func keyboardWillShow(notification: NSNotification) 
{
      // Your Code Here
}
func keyboardWillHide(notification: NSNotification)
{  
   //Your Code Here     
}

您可以分别在两个版本的Swift上执行键盘通知。

添加objserver:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: .UIKeyboardWillShow, object: nil)

呼叫功能Swift 3

func keyboardDidShow() {
          print("keyboardDidShow")
       }

swift 4

中的呼叫功能
@objc func keyboardDidShow() {
      print("keyboardDidShow")
   }
  NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillShow:")), name:UIResponder.keyboardWillShowNotification, object: nil);
    NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillHide:")), name:UIResponder.keyboardWillHideNotification, object: nil);

这是对我有用的最佳解决方案(从"让我们构建该应用程序" YouTube频道)

class ChatVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
// reference to your UIView with message TextField
    @IBOutlet weak var ChatView: UIView!   

// bottom constrain to your UIView (in my case ChatView)
    var bottomConstraint: NSLayoutConstraint?  
    override func viewDidLoad() {
        super.viewDidLoad()
// add some text in the placeholder if you want
        messageField.placeholder = "Type your message.." 
// here we add two notifications for showing and hiding the keyboard
        NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardNotification), name: UIResponder.keyboardWillHideNotification, object: nil)

// defines the start position for message textField that will be shown on the screen
        bottomConstraint = NSLayoutConstraint(item: ChatViewField!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: -40)    
        view.addConstraint(bottomConstraint!)    
    }
// handles notifications for both cases when keyboard pops up and disappears  
  @objc func handleKeyboardNotification(notification: NSNotification){
        if let userInfo = notification.userInfo {
            let keyboardFrame =  (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
            print(keyboardFrame)
            let isKeyboardShowing = notification.name == UIResponder.keyboardWillShowNotification
            bottomConstraint?.constant = isKeyboardShowing ? -keyboardFrame.height : -40
// makes animation at the same time as the keyboard
UIView.animate(withDuration: 0, delay: 0, options: UIView.AnimationOptions.curveEaseOut, animations: {
                self.view.layoutIfNeeded()
            }) { (completed) in    
            }   
        }
    }

您可以创建具有此逻辑的协议,并且您的UiviewController实现了它,在viewDidLoad中,您调用config方法绑定它。

我在底部使用约束来移动与键盘相同的动画的整个视图。

在这里您有一个使用Zafar007的答案的示例:

protocol ViewControllerKeyboardType {
    var bottomConstraint: NSLayoutConstraint! { get set }
    
    func configKeyboardNotification()
    
    func keyboardWillChangeHandler(notification: NSNotification)
}
extension ViewControllerKeyboardType where Self: UIViewController {
    func keyboardWillChangeHandler(notification: NSNotification) {
        let duration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double ?? 0.0
        let curve = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt ?? UIView.AnimationOptions.curveLinear.rawValue
        let curFrame = (notification.userInfo![UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y
        
        UIView.animate(withDuration: duration, delay: 0, options: UIView.AnimationOptions(rawValue: curve)) {
            self.bottomConstraint.constant = self.bottomConstraint.constant - deltaY
            self.view.layoutIfNeeded()
        }
    }
    
    func configKeyboardNotification() {
        NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification, object: nil, queue: nil) { [weak self] (notification) in
            self?.keyboardWillChangeHandler(notification: notification as NSNotification)
        }
    }
}

用法:

class MyViewController: UIViewController, ViewControllerKeyboardType {
    @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.configKeyboardNotification()
    }
}

如果您是像我这样的白痴,而花哨的Combine

UIViewController的简单扩展:

import UIKit
import Combine 
extension Notification {
    var keyboardHeight: CGFloat {
        return (userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0
    }
}
enum KeyboardState {
    case willShow
    case willHide
}
struct KeyboardObject: Equatable {
    var state: KeyboardState
    var height: CGFloat
}
extension UIViewController {
    private var keyboardWillShowPublisher: AnyPublisher<KeyboardObject, Never> {
        NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification,object: nil)
        .compactMap {
            return KeyboardObject(state: .willShow, height: $0.keyboardHeight)
        }.eraseToAnyPublisher()
    }
    
    private var keyboardWillHidePublisher: AnyPublisher<KeyboardObject, Never> {
        NotificationCenter.default
            .publisher(for: UIResponder.keyboardWillHideNotification,object: nil)
            .compactMap { _ in
                return KeyboardObject(state: .willHide, height: 0.0)
            }.eraseToAnyPublisher()
    }
    
    func keyboardListener() -> AnyPublisher<KeyboardObject, Never> {
        Publishers.Merge(keyboardWillShowPublisher, keyboardWillHidePublisher)
            .removeDuplicates()
            .eraseToAnyPublisher()
    }
}

在您的UIViewController中:

import UIKit
import Combine
final class SomeVC: UIViewController {
    var keyboardPublisher: AnyCancellable?
    private var flowLayoutConstraint: NSLayoutConstraint!
    private let defaults = UserDefaults.standard
    override func viewWillAppear(_ animated: Bool) {
        keyboardPublisher = self.keyboardListener()
            .sink(receiveValue: { [unowned self] keyboard in
                switch keyboard.state {
                case .willShow:
                    manageKeyboardChange(value: keyboard.height)
                case .willHide:
                // I used a value saved in my userDefaults, but just set it back to the original constraint for that view without the keyboard
                    manageKeyboardChange(value: defaults.double(forKey: "opaqueHeight"))
                }
            })
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        keyboardPublisher?.cancel()
    }
    
    func manageKeyboardChange(value: CGFloat) {
        self.flowLayoutConstraint.constant = value
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations:  { [weak self] in
            self?.view.layoutIfNeeded()
        }, completion: nil)
        
        print("CHANGE")
    }
}

最新更新