Swift 3中如何编写键盘通知

25

我正在尝试将这段代码更新为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)`

不幸的是,这不能帮我解决问题,反而会导致更多的错误。

请问有人解决了这个问题吗?

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


3
可能是Swift 3 NSNotificationCenter Keyboardwillshow/hide的重复问题。 - LC 웃
有点不同 - 引用的问题是关于键盘显示/隐藏功能。这个问题是关于通知设置的。 - ICL1901
1
好的,请告诉我是否有帮助。 - LC 웃
谢谢Anish,我还在努力想弄清楚如何编写通知本身。 - ICL1901
12个回答

39

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

1
你确定你打对了吗?两个都写成了 UIWindow.keyboardWillShowNotification - ICL1901

33

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
 }

谢谢!我正准备修改我的问题。 - ICL1901
使用 UIKeyboardDidShow 比使用 UIKeyboardWillShow 更好,还是基本上一样的东西? - Michael Hsu
@MichaelHsu 这取决于你。如果你需要在键盘出现之前调用函数,那么你可以使用 keyboardWillShow 方法。否则,你可以使用 UIKeyboardDidShow,它会在键盘出现后调用。 - ZAFAR007
@MichaelHsu 很少需要使用 didShow;通常您希望键盘避让动画是动态的,并且复制键盘的动画曲线和持续时间。 - Dan Rosenstark
3
虽然这个解决方案可行,但值得一提的是,为了避免内存泄漏,您需要在viewWillDisappear中删除通知观察器。只需添加以下代码:override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) } - nja

25

我通过这样编写代码来解决了这个问题

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

23

对于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
    }

这对我有用。谢谢。 - RJB

13

您可以使用经过类型检查的 #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 选择器的更多信息,请参见 Rickster 的详细回答


太棒了,我刚刚用了这个!顺便提一下,如果有人遇到我的问题:在实现keyboardWillShowkeyboardWillHide时,不要将它们设为私有函数,否则会出现编译器错误。 - Sami

11

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

3

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

}

键盘的显示和隐藏

func keyboardWillShow(notification: NSNotification) 
{

      // Your Code Here
}

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

2
你可以分别在Swift的两个版本上执行键盘通知。
添加观察者:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow), name: .UIKeyboardWillShow, object: nil)

调用Swift 3函数

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

在Swift 4中调用函数

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

我们为什么要在函数前使用@objc关键字?是否有纯Swift代码的方法来实现4? - Suresh Durishetti
2
由于keyboardDidShow方法是从Objective C中调用的,因此在调用该方法之前,Swift 4要求您添加@objc关键字。 - Sunil M.

2
  NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillShow:")), name:UIResponder.keyboardWillShowNotification, object: nil);
    NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillHide:")), name:UIResponder.keyboardWillHideNotification, object: nil);

1
您可以创建一个具有此逻辑的协议,然后您的UIViewController实现它,在viewDidLoad中调用配置方法进行绑定。
我使用底部的约束来移动整个视图,以与键盘相同的动画方式移动。
这里有一个使用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()
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接