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.
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 appelerCGRectValue
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)
// ...
}
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() })
}
} }
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:
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.
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()
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
}
Vous pouvez utiliser cette ligne pour votre ligne
var keyboardSize:CGSize = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)!.CGRectValue().size
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)
}
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()
}
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
Journal
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;
}