24

I'm trying to update this code to swift 3:

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

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

So far, I've just tried the auto corrections given by the compiler. This results in code like this:

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

Unfortunately, that doesn't take me far, resulting in additional errors.

Has anyone solved this please?

Please note that I'm just trying how to write the notifications. I'm not (yet) trying to fix the notification functions.. Thanks

Vadim Kotov
  • 7,766
  • 8
  • 46
  • 61
ICL1901
  • 7,416
  • 13
  • 90
  • 133

11 Answers11

38

Swift 4.2 Xcode 10 (10L213o)

The main changes compared with Swift 3 are in the UIWindow.keyboardWillShowNotification and UIWindow.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) {}
fssilva
  • 895
  • 11
  • 7
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)
}

You can also get keyboard info using below code inside these methods.

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
 }
ZAFAR007
  • 2,873
  • 1
  • 31
  • 42
  • Thanks! I was about to revise my question. – ICL1901 Jan 25 '18 at 18:48
  • Is it better to use `UIKeyboardDidShow` rather than `UIKeyboardWillShow`, or is it basically the same thing? – Michael Hsu May 06 '18 at 01:43
  • @MichaelHsu It is depends on you. If you need to call function before keyboard appearance, then you can use `keyboardWillShow` method otherwise you can use `UIKeyboardDidShow` that will call after keyboard appearance – ZAFAR007 May 10 '18 at 08:58
  • @MichaelHsu it's very rare that you want to use `didShow`; you generally want your keyboard avoiding to be animated and copy the animation curve and duration of the keyboard. – Dan Rosenstark May 13 '18 at 13:37
  • 2
    Although this solution works, it's worth a mention that you need to remove notification observer in viewWillDisappear to avoid memory leak. Simply add: `override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) }` – nja Sep 17 '18 at 15:09
25

I fixed this issue by writing the code like this

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: .UIKeyboardWillShow, object: nil)
Ben Rawner
  • 401
  • 1
  • 5
  • 3
23

For Swift 4.2 .UIKeyboardWillShow is renamed to UIResponder.keyboardWillShowNotification and .UIKeyboardWillHide is renamed to 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
    }
13

You can replace the deprecated string literal Selector with the type-checked #selector(Class.method) pair:

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

center.addObserver(self,
                   selector: #selector(keyboardWillHide(_:)),
                   name: .UIKeyboardWillHide,
                   object: nil)

The #selector syntax is much safer, since Swift is able to check at compile time that the specified method actually exists.

For more information about Swift selectors, see rickster's detailed answer.

Community
  • 1
  • 1
  • Awesome I just used this! Side note in case anyone runs in my issue: when implementing the `keyboardWillShow` and the `keyboardWillHide`, do not make them private functions or you will have a compiler error. – Sami Jan 07 '17 at 18:53
10

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)
    }
    
Community
  • 1
  • 1
Sergey
  • 318
  • 3
  • 11
3

In 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 and Hide

func keyboardWillShow(notification: NSNotification) 
{

      // Your Code Here
}

func keyboardWillHide(notification: NSNotification)
{  
   //Your Code Here     
}
Amul4608
  • 1,292
  • 13
  • 29
2

You can perform keyboard notification on both version of Swift respectively.

Add Objserver:

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

Call function swift 3

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

Call function In swift 4

@objc func keyboardDidShow() {
      print("keyboardDidShow")
   }
Sunil M.
  • 564
  • 4
  • 17
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);
SCS
  • 425
  • 2
  • 12
1

Here is the best solution that works for me as far (used from "Lets Build That App" YouTube channel)

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    
            }   
        }
    }
zmag
  • 7,281
  • 12
  • 30
  • 38
Ivan.I
  • 11
  • 2
1

You can create a protocol that has this logic and your UIViewController implements it, in the viewDidLoad you call the config method to bind it.

I use a constraint at the bottom to move the whole view with the same animation as the keyboard.

Here you have an example using 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)
        }
    }
}

Usage:

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