Obtenir la taille du clavier à partir de UserInfo dans Swift

j'ai essayé d'ajouter du code pour déplacer ma vue vers le haut quand le clavier apparaît, cependant, j'ai des problèmes en essayant de traduire les exemples de L'Objectif-C dans Swift. J'ai fait quelques progrès, mais je suis bloqué sur une ligne particulière.

ce sont les deux tutoriels / questions que j'ai suivi:

Comment déplacer le contenu de UIViewController le haut, comme le Clavier s'affiche à l'aide de Swift http://www.ioscreator.com/tutorials/move-view-when-keyboard-appears

voici le code que j'ai actuellement:

override func viewWillAppear(animated: Bool) {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func keyboardWillShow(notification: NSNotification) {
    var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
    UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    let frame = self.budgetEntryView.frame
    frame.origin.y = frame.origin.y - keyboardSize
    self.budgetEntryView.frame = frame
}

func keyboardWillHide(notification: NSNotification) {
    //
}

En ce moment, je reçois une erreur sur cette ligne:

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))

si quelqu'un pouvait me faire savoir ce que cette ligne de code devrait être, je devrais réussir à comprendre le reste moi-même.

75
demandé sur Community 2014-08-22 19:54:21

10 réponses

il y a des problèmes dans votre ligne

var keyboardSize = notification.userInfo(valueForKey(UIKeyboardFrameBeginUserInfoKey))
  • notification.userInfo retourne un optionnel dictionary [NSObject : AnyObject]? , il faut donc le déballer avant d'accéder à ses valeurs.
  • L'Objective-C NSDictionary est mappé à une Swift natif de Dictionnaire, de sorte que vous devez utilisez la syntaxe dictionary subscript ( dict[key] ) pour accéder aux valeurs.
  • la valeur doit être coulée à NSValue pour que vous puissiez appeler CGRectValue dessus.

tout cela peut être réalisé avec une combinaison d'assignation optionnelle, d'enchaînement optionnel et mentions facultatives:

if let userInfo = notification.userInfo {
   if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
       // ...
   } else {
       // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
   }
} else {
   // no userInfo dictionary in notification
}

ou en une seule étape:

if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    // ...
}

mise à jour pour Swift 3.0.1 (Xcode 8.1):

if let userInfo = notification.userInfo {
    if let keyboardSize = userInfo[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
        let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
        // ...
    } else {
        // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
    }
} else {
    // no userInfo dictionary in notification
}

ou en une seule étape:

if let keyboardSize = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? CGRect {
    let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
    // ...
}
179
répondu Martin R 2017-01-18 10:58:18

pour encore moins de code envisager de regarder ce

ça m'a été très utile. Vous devez juste inclure la contrainte de vue dans le contrôleur de vue et utiliser les deux observateurs que vous avez ajoutés. Ensuite, il suffit d'utiliser les méthodes suivantes (il est supposé ici vous déplacer une tableView)

func keyboardWillShow(sender: NSNotification) {
        if let userInfo = sender.userInfo {
            if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().size.height {
                tableViewBottomConstraint.constant = keyboardHeight
                UIView.animateWithDuration(0.25, animations: { () -> Void in
                    self.view.layoutIfNeeded()
                })
            }
        }
    }

et

func keyboardWillHide(sender: NSNotification) {
if let userInfo = sender.userInfo {
  if let keyboardHeight = userInfo[UIKeyboardFrameEndUserInfoKey]?.CGRectValue().size.height {
    tableViewBottomConstraint.constant = 0.0
    UIView.animateWithDuration(0.25, animations: { () -> Void in self.view.layoutIfNeeded() })
  }
} }
17
répondu Nicholas 2015-03-29 07:42:38

si vous utilisez storyboard, plutôt que de manipuler la vue elle-même, vous pouvez profiter de l'auto-disposition.

(C'est une version nettoyée de la réponse de Nicolas)

mettre en place un centre de notification pour vous informer de l'apparition et de la disparition du clavier:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)

}

et assurez-vous que vous retirez les observateurs lorsque vous n'en avez plus besoin:

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
}

à l'Intérieur storyboard, définissez la contrainte du bas. Créer un exutoire de cette contrainte:

enter image description here

et définir la propriété constante de la contrainte lorsque le clavier est affiché ou caché:

func keyboardWillShow(notification: NSNotification) {
    guard let keyboardHeight = (notification.userInfo! as NSDictionary).objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue.size.height else {
        return
    }
    nameOfOutlet.constant = keyboardHeight
    view.layoutIfNeeded()
}

func keyboardWillHide(notification: NSNotification) {
    nameOfOutlet.constant = 0.0
    view.layoutIfNeeded()
}

maintenant, chaque fois que le clavier apparaît ou disparaît, autolayout s'occupera de tout.

10
répondu DudeOnRock 2016-08-16 04:53:33

cela m'a aidé: https://developer.apple.com/library/ios/samplecode/UICatalog/Listings/Swift_UICatalog_TextViewController_swift.html

let userInfo = notification.userInfo!

let animationDuration: NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as NSNumber).doubleValue
let keyboardScreenBeginFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as NSValue).CGRectValue()
let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
3
répondu Paul 2015-02-24 20:21:11

Swift 2

func keyboardWasShown(notification:NSNotification) {
        guard let info:[NSObject:AnyObject] = notification.userInfo,
            let keyboardSize:CGSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size else { return }

        let insets:UIEdgeInsets = UIEdgeInsetsMake(self.scrollView.contentInset.top, 0.0, keyboardSize.height, 0.0)

        self.scrollView.contentInset = insets
        self.scrollView.scrollIndicatorInsets = insets
    }

Swift 3

func keyboardWasShown(notification:NSNotification) {
    guard let info:[AnyHashable:Any] = notification.userInfo,
        let keyboardSize:CGSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size else { return }

    let insets:UIEdgeInsets = UIEdgeInsets(top: self.scrollView.contentInset.top, left: 0.0, bottom: keyboardSize.height, right: 0.0)

    self.scrollView.contentInset = insets
    self.scrollView.scrollIndicatorInsets = insets
}
3
répondu Barlow Tucker 2017-02-01 16:42:46

Vous pouvez utiliser cette ligne pour votre ligne

var keyboardSize:CGSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue().size
1
répondu Avinash 2015-01-19 09:33:37

Swift 3: mise à jour

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
}
1
répondu Kevin Sabbe 2016-12-18 17:34:06

Swift 3.0

voici un exemple de récupération de la taille du clavier et de l'utiliser pour animer une vue vers le haut. Dans mon cas, je déplace un uivi contenant mes champs UITextFields vers le haut quand un utilisateur commence à taper afin qu'ils puissent remplir un formulaire et toujours voir le bouton Soumettre en bas.

j'ai ajouté une sortie à la contrainte d'espace de fond de la vue que je voulais animer et l'ai nommé myViewsBottomSpaceConstraint :

@IBOutlet weak var myViewsBottomSpaceConstraint: NSLayoutConstraint!

j'ai ensuite ajouté le code suivant à ma classe swift:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
}

func keyboardWillShow(notification: NSNotification) {

    let userInfo = notification.userInfo as! [String: NSObject] as NSDictionary
    let keyboardFrame = userInfo.value(forKey: UIKeyboardFrameEndUserInfoKey) as! CGRect
    let keyboardHeight = keyboardFrame.height
    myViewsBottomSpaceConstraint.constant = keyboardHeight
    view.layoutIfNeeded()
}

func keyboardWillHide(notification: NSNotification) {
    myViewsBottomSpaceConstraint.constant = 0.0
    view.layoutIfNeeded()
}
0
répondu mobilecat 2017-01-08 16:48:02

détails

xCode 8.2.1, swift 3

Code

KeyboardNotifications

import Foundation

class KeyboardNotifications {

    fileprivate var _isEnabled: Bool
    fileprivate var notifications:  [KeyboardNotificationsType]
    fileprivate var delegate: KeyboardNotificationsDelegate

    init(notifications: [KeyboardNotificationsType], delegate: KeyboardNotificationsDelegate) {
        _isEnabled = false
        self.notifications = notifications
        self.delegate = delegate
    }

    deinit {
        if isEnabled {
            isEnabled = false
        }
    }
}

// MARK: - enums

extension KeyboardNotifications {

    enum KeyboardNotificationsType {
        case willShow, willHide, didShow, didHide

        var selector: Selector {
            switch self {

            case .willShow:
                return #selector(KeyboardNotifications.keyboardWillShow(notification:))

            case .willHide:
                return #selector(KeyboardNotifications.keyboardWillHide(notification:))

            case .didShow:
                return #selector(KeyboardNotifications.keyboardDidShow(notification:))

            case .didHide:
                return #selector(KeyboardNotifications.keyboardDidHide(notification:))

            }
        }

        var notificationName: NSNotification.Name {
            switch self {

            case .willShow:
                return .UIKeyboardWillShow

            case .willHide:
                return .UIKeyboardWillHide

            case .didShow:
                return .UIKeyboardDidShow

            case .didHide:
                return .UIKeyboardDidHide
            }
        }
    }
}

// MARK: - isEnabled

extension KeyboardNotifications {

    private func addObserver(type: KeyboardNotificationsType) {
        NotificationCenter.default.addObserver(self, selector: type.selector, name: type.notificationName, object: nil)
        print("\(type.notificationName.rawValue) inited")
    }

    var isEnabled: Bool {
        set {
            if newValue {

                for notificaton in notifications {
                    addObserver(type: notificaton)
                }
            } else {
                NotificationCenter.default.removeObserver(self)
                print("Keyboard notifications deinited")
            }
            _isEnabled = newValue
        }

        get {
            return _isEnabled
        }
    }

}

// MARK: - Notification functions

extension KeyboardNotifications {

    @objc
    func keyboardWillShow(notification: NSNotification) {
        delegate.keyboardWillShow?(notification: notification)
    }

    @objc
    func keyboardWillHide(notification: NSNotification) {
        delegate.keyboardWillHide?(notification: notification)
    }

    @objc
    func keyboardDidShow(notification: NSNotification) {
        delegate.keyboardDidShow?(notification: notification)
    }

    @objc
    func keyboardDidHide(notification: NSNotification) {
        delegate.keyboardDidHide?(notification: notification)
    }
}

KeyboardNotificationsDelegate

import Foundation

@objc
protocol KeyboardNotificationsDelegate {

    @objc optional func keyboardWillShow(notification: NSNotification)
    @objc optional func keyboardWillHide(notification: NSNotification)
    @objc optional func keyboardDidShow(notification: NSNotification)
    @objc optional func keyboardDidHide(notification: NSNotification)
}

Utilisation

 class ViewController: UIViewController {
      private var keyboardNotifications: KeyboardNotifications!
      override func viewDidLoad() {
           super.viewDidLoad()
           ...
            keyboardNotifications = KeyboardNotifications(notifications: [.willShow, .willHide, .didShow, .didHide], delegate: self)
      }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        keyboardNotifications.isEnabled = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        keyboardNotifications.isEnabled = false
    }

 }

 extension ViewController: KeyboardNotificationsDelegate {

    // If you don't need this func you can remove it
    func keyboardWillShow(notification: NSNotification) {
           ...
    }

    // If you don't need this func you can remove it
    func keyboardWillHide(notification: NSNotification) {
           ...
    }

    // If you don't need this func you can remove it
    func keyboardDidShow(notification: NSNotification) {
           ...
    }

    // If you don't need this func you can remove it
    func keyboardDidHide(notification: NSNotification) {
           ...
    }
}

Échantillon Complet

import UIKit

class ViewController: UIViewController {

    private var keyboardNotifications: KeyboardNotifications!
    private var textField = UITextField(frame: CGRect(x: 40, y: 40, width: 200, height: 30))

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(textField)

        // when you will tap on view (background) the keyboard will hide
        // read about view.disableKeybordWhenTapped here: http://stackoverflow.com/a/42187286/4488252
        view.disableKeybordWhenTapped = true

        keyboardNotifications = KeyboardNotifications(notifications: [.willShow, .willHide, .didShow, .didHide], delegate: self)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        keyboardNotifications.isEnabled = true
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        keyboardNotifications.isEnabled = false
    }

}

 extension ViewController: KeyboardNotificationsDelegate {

    // If you don't need this func you can remove it
    func keyboardWillShow(notification: NSNotification) {
        print("keyboardWillShow")
        let userInfo = notification.userInfo as! [String: NSObject]
        let keyboardFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as! CGRect
        print("keyboardFrame: \(keyboardFrame)")
    }

    // If you don't need this func you can remove it
    func keyboardWillHide(notification: NSNotification) {
        print("keyboardWillHide")
    }

    // If you don't need this func you can remove it
    func keyboardDidShow(notification: NSNotification) {
        print("keyboardDidShow")
    }

    // If you don't need this func you can remove it
    func keyboardDidHide(notification: NSNotification) {
 print("keyboardDidHide")
    }
}

résultat

enter image description here

Journal

enter image description here

0
répondu Vasily Bodnarchuk 2017-03-06 17:20:54

pour la xamarine, vous pouvez utiliser c#6

private void KeyboardWillChangeFrame(NSNotification notification)
{
        var keyboardSize = notification.UserInfo.ValueForKey(UIKeyboard.FrameEndUserInfoKey) as NSValue;
        if (keyboardSize != null)
        {
            var rect= keyboardSize.CGRectValue;
            //do your stuff here
        }
}

c#7

  private void KeyboardWillChangeFrame(NSNotification notification)
   {
       if (!(notification.UserInfo.ValueForKey(UIKeyboard.FrameEndUserInfoKey) is NSValue keyboardSize)) return;
       var rect= keyboardSize.CGRectValue;
   }
0
répondu marcel 2017-09-19 19:45:23