【问题标题】:How to write Keyboard notifications in Swift 3如何在 Swift 3 中编写键盘通知
【发布时间】:2016-10-18 23:04:30
【问题描述】:

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

不幸的是,这并没有让我走得太远,导致了额外的错误。

请问有人解决了吗?

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

【问题讨论】:

  • 有点不同 - 引用的问题是关于键盘显示/隐藏功能。这个问题是关于通知设置的。
  • 好的,如果没有帮助,请告诉我
  • 谢谢 Anish,我还在想办法自己写通知。

标签: ios swift swift3 nsnotificationcenter


【解决方案1】:

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

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

这里有一个使用 ZAFAR007's answer 的示例:

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

【讨论】:

  • 谢谢。这很有帮助
【解决方案2】:

斯威夫特 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
 }

【讨论】:

  • 谢谢!我正要修改我的问题。
  • 使用UIKeyboardDidShow而不是UIKeyboardWillShow更好,还是基本一样?
  • @MichaelHsu 这取决于你。如果你需要在键盘出现之前调用函数,那么你可以使用keyboardWillShow方法,否则你可以使用UIKeyboardDidShow在键盘出现后调用
  • @MichaelHsu 你很少想用didShow;您通常希望您的键盘避免动画并复制键盘的动画曲线和持续时间。
  • 虽然此解决方案有效,但值得一提的是,您需要在 viewWillDisappear 中删除通知观察者以避免内存泄漏。只需添加:override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) }
【解决方案3】:

这是目前最适合我的解决方案(来自“Lets Build That App”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    
            }   
        }
    }

【讨论】:

    【解决方案4】:

    Swift 5.1 + 组合 + 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)
        }
        
    

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 您确定输入正确吗?都说UIWindow.keyboardWillShowNotification
      【解决方案6】:
        NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillShow:")), name:UIResponder.keyboardWillShowNotification, object: nil);
          NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillHide:")), name:UIResponder.keyboardWillHideNotification, object: nil);
      

      【讨论】:

        【解决方案7】:

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

        【讨论】:

        • 这是为我做的。谢谢
        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

          您可以分别在两个版本的 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")
             }
          

          【讨论】:

          • 为什么要使用@objc关键字来运行? 4 有没有纯 swift 代码的方法?
          • 由于keyboardDidShow方法从Objective C调用,swift 4坚持你在调用方法之前添加@objc关键字。
          【解决方案10】:

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

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

          【讨论】:

            【解决方案11】:

            您可以将已弃用的字符串文字 Selector 替换为经过类型检查的 #selector(Class.method) 对:

            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's detailed answer

            【讨论】:

            • 太棒了,我刚用过这个!如果有人遇到我的问题,请注意:在实现 keyboardWillShowkeyboardWillHide 时,不要将它们设为私有函数,否则会出现编译器错误。
            猜你喜欢
            • 2019-07-10
            • 2017-04-11
            • 2017-12-19
            • 2016-12-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多